*** This commit represents a complete reformatting of the LLDB source code
*** to conform to clang-format’s LLVM style. This kind of mass change has
*** two obvious implications:
Firstly, merging this particular commit into a downstream fork may be a huge
effort. Alternatively, it may be worth merging all changes up to this commit,
performing the same reformatting operation locally, and then discarding the
merge for this particular commit. The commands used to accomplish this
reformatting were as follows (with current working directory as the root of
the repository):
find . \( -iname "*.c" -or -iname "*.cpp" -or -iname "*.h" -or -iname "*.mm" \) -exec clang-format -i {} +
find . -iname "*.py" -exec autopep8 --in-place --aggressive --aggressive {} + ;
The version of clang-format used was 3.9.0, and autopep8 was 1.2.4.
Secondly, “blame” style tools will generally point to this commit instead of
a meaningful prior commit. There are alternatives available that will attempt
to look through this change and find the appropriate prior commit. YMMV.
llvm-svn: 280751
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
# Be sure to add the python path that points to the LLDB shared library.
|
||||
#
|
||||
# # To use this in the embedded python interpreter using "lldb" just
|
||||
# import it with the full path using the "command script import"
|
||||
# import it with the full path using the "command script import"
|
||||
# command
|
||||
# (lldb) command script import /path/to/cmdtemplate.py
|
||||
#----------------------------------------------------------------------
|
||||
@@ -14,22 +14,51 @@ import commands
|
||||
import optparse
|
||||
import shlex
|
||||
|
||||
|
||||
def create_framestats_options():
|
||||
usage = "usage: %prog [options]"
|
||||
description='''This command is meant to be an example of how to make an LLDB command that
|
||||
description = '''This command is meant to be an example of how to make an LLDB command that
|
||||
does something useful, follows best practices, and exploits the SB API.
|
||||
Specifically, this command computes the aggregate and average size of the variables in the current frame
|
||||
and allows you to tweak exactly which variables are to be accounted in the computation.
|
||||
'''
|
||||
parser = optparse.OptionParser(description=description, prog='framestats',usage=usage)
|
||||
parser.add_option('-i', '--in-scope', action='store_true', dest='inscope', help='in_scope_only = True', default=False)
|
||||
parser.add_option('-a', '--arguments', action='store_true', dest='arguments', help='arguments = True', default=False)
|
||||
parser.add_option('-l', '--locals', action='store_true', dest='locals', help='locals = True', default=False)
|
||||
parser.add_option('-s', '--statics', action='store_true', dest='statics', help='statics = True', default=False)
|
||||
parser = optparse.OptionParser(
|
||||
description=description,
|
||||
prog='framestats',
|
||||
usage=usage)
|
||||
parser.add_option(
|
||||
'-i',
|
||||
'--in-scope',
|
||||
action='store_true',
|
||||
dest='inscope',
|
||||
help='in_scope_only = True',
|
||||
default=False)
|
||||
parser.add_option(
|
||||
'-a',
|
||||
'--arguments',
|
||||
action='store_true',
|
||||
dest='arguments',
|
||||
help='arguments = True',
|
||||
default=False)
|
||||
parser.add_option(
|
||||
'-l',
|
||||
'--locals',
|
||||
action='store_true',
|
||||
dest='locals',
|
||||
help='locals = True',
|
||||
default=False)
|
||||
parser.add_option(
|
||||
'-s',
|
||||
'--statics',
|
||||
action='store_true',
|
||||
dest='statics',
|
||||
help='statics = True',
|
||||
default=False)
|
||||
return parser
|
||||
|
||||
|
||||
def the_framestats_command(debugger, command, result, dict):
|
||||
# Use the Shell Lexer to properly parse up command options just like a
|
||||
# Use the Shell Lexer to properly parse up command options just like a
|
||||
# shell would
|
||||
command_args = shlex.split(command)
|
||||
parser = create_framestats_options()
|
||||
@@ -38,9 +67,9 @@ def the_framestats_command(debugger, command, result, dict):
|
||||
except:
|
||||
# if you don't handle exceptions, passing an incorrect argument to the OptionParser will cause LLDB to exit
|
||||
# (courtesy of OptParse dealing with argument errors by throwing SystemExit)
|
||||
result.SetError ("option parsing failed")
|
||||
result.SetError("option parsing failed")
|
||||
return
|
||||
|
||||
|
||||
# in a command - the lldb.* convenience variables are not to be used
|
||||
# and their values (if any) are undefined
|
||||
# this is the best practice to access those objects from within a command
|
||||
@@ -51,26 +80,33 @@ def the_framestats_command(debugger, command, result, dict):
|
||||
if not frame.IsValid():
|
||||
return "no frame here"
|
||||
# from now on, replace lldb.<thing>.whatever with <thing>.whatever
|
||||
variables_list = frame.GetVariables(options.arguments, options.locals, options.statics, options.inscope)
|
||||
variables_list = frame.GetVariables(
|
||||
options.arguments,
|
||||
options.locals,
|
||||
options.statics,
|
||||
options.inscope)
|
||||
variables_count = variables_list.GetSize()
|
||||
if variables_count == 0:
|
||||
print >> result, "no variables here"
|
||||
return
|
||||
total_size = 0
|
||||
for i in range(0,variables_count):
|
||||
for i in range(0, variables_count):
|
||||
variable = variables_list.GetValueAtIndex(i)
|
||||
variable_type = variable.GetType()
|
||||
total_size = total_size + variable_type.GetByteSize()
|
||||
average_size = float(total_size) / variables_count
|
||||
print >>result, "Your frame has %d variables. Their total size is %d bytes. The average size is %f bytes" % (variables_count,total_size,average_size)
|
||||
print >>result, "Your frame has %d variables. Their total size is %d bytes. The average size is %f bytes" % (
|
||||
variables_count, total_size, average_size)
|
||||
# not returning anything is akin to returning success
|
||||
|
||||
def __lldb_init_module (debugger, dict):
|
||||
# This initializer is being run from LLDB in the embedded command interpreter
|
||||
# Make the options so we can generate the help text for the new LLDB
|
||||
|
||||
def __lldb_init_module(debugger, dict):
|
||||
# This initializer is being run from LLDB in the embedded command interpreter
|
||||
# Make the options so we can generate the help text for the new LLDB
|
||||
# command line command prior to registering it with LLDB below
|
||||
parser = create_framestats_options()
|
||||
the_framestats_command.__doc__ = parser.format_help()
|
||||
# Add any commands contained in this module to LLDB
|
||||
debugger.HandleCommand('command script add -f cmdtemplate.the_framestats_command framestats')
|
||||
debugger.HandleCommand(
|
||||
'command script add -f cmdtemplate.the_framestats_command framestats')
|
||||
print 'The "framestats" command has been installed, type "help framestats" or "framestats --help" for detailed help.'
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,15 +1,15 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
# This module will enable GDB remote packet logging when the
|
||||
# This module will enable GDB remote packet logging when the
|
||||
# 'start_gdb_log' command is called with a filename to log to. When the
|
||||
# 'stop_gdb_log' command is called, it will disable the logging and
|
||||
# 'stop_gdb_log' command is called, it will disable the logging and
|
||||
# print out statistics about how long commands took to execute and also
|
||||
# will primnt ou
|
||||
# Be sure to add the python path that points to the LLDB shared library.
|
||||
#
|
||||
# To use this in the embedded python interpreter using "lldb" just
|
||||
# import it with the full path using the "command script import"
|
||||
# import it with the full path using the "command script import"
|
||||
# command. This can be done from the LLDB command line:
|
||||
# (lldb) command script import /path/to/gdbremote.py
|
||||
# Or it can be added to your ~/.lldbinit file so this module is always
|
||||
@@ -23,13 +23,16 @@ import shlex
|
||||
import re
|
||||
import tempfile
|
||||
|
||||
|
||||
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
|
||||
thread safe logging. Follow a call to this function with a call to "stop_gdb_log"
|
||||
in order to dump out the commands.'''
|
||||
global log_file
|
||||
if log_file:
|
||||
result.PutCString ('error: logging is already in progress with file "%s"', log_file)
|
||||
result.PutCString(
|
||||
'error: logging is already in progress with file "%s"',
|
||||
log_file)
|
||||
else:
|
||||
args_len = len(args)
|
||||
if args_len == 0:
|
||||
@@ -38,36 +41,52 @@ def start_gdb_log(debugger, command, result, dict):
|
||||
log_file = args[0]
|
||||
|
||||
if log_file:
|
||||
debugger.HandleCommand('log enable --threadsafe --timestamp --file "%s" gdb-remote packets' % log_file);
|
||||
result.PutCString ("GDB packet logging enable with log file '%s'\nUse the 'stop_gdb_log' command to stop logging and show packet statistics." % log_file)
|
||||
debugger.HandleCommand(
|
||||
'log enable --threadsafe --timestamp --file "%s" gdb-remote packets' %
|
||||
log_file)
|
||||
result.PutCString(
|
||||
"GDB packet logging enable with log file '%s'\nUse the 'stop_gdb_log' command to stop logging and show packet statistics." %
|
||||
log_file)
|
||||
return
|
||||
|
||||
result.PutCString ('error: invalid log file path')
|
||||
result.PutCString (usage)
|
||||
result.PutCString('error: invalid log file path')
|
||||
result.PutCString(usage)
|
||||
|
||||
|
||||
def parse_time_log(debugger, command, result, dict):
|
||||
# Any commands whose names might be followed by more valid C identifier
|
||||
# Any commands whose names might be followed by more valid C identifier
|
||||
# characters must be listed here
|
||||
command_args = shlex.split(command)
|
||||
parse_time_log_args (command_args)
|
||||
parse_time_log_args(command_args)
|
||||
|
||||
|
||||
def parse_time_log_args(command_args):
|
||||
usage = "usage: parse_time_log [options] [<LOGFILEPATH>]"
|
||||
description='''Parse a log file that contains timestamps and convert the timestamps to delta times between log lines.'''
|
||||
parser = optparse.OptionParser(description=description, prog='parse_time_log',usage=usage)
|
||||
parser.add_option('-v', '--verbose', action='store_true', dest='verbose', help='display verbose debug info', default=False)
|
||||
description = '''Parse a log file that contains timestamps and convert the timestamps to delta times between log lines.'''
|
||||
parser = optparse.OptionParser(
|
||||
description=description,
|
||||
prog='parse_time_log',
|
||||
usage=usage)
|
||||
parser.add_option(
|
||||
'-v',
|
||||
'--verbose',
|
||||
action='store_true',
|
||||
dest='verbose',
|
||||
help='display verbose debug info',
|
||||
default=False)
|
||||
try:
|
||||
(options, args) = parser.parse_args(command_args)
|
||||
except:
|
||||
return
|
||||
for log_file in args:
|
||||
parse_log_file (log_file, options)
|
||||
parse_log_file(log_file, options)
|
||||
|
||||
|
||||
def parse_log_file(file, options):
|
||||
'''Parse a log file that was contains timestamps. These logs are typically
|
||||
generated using:
|
||||
(lldb) log enable --threadsafe --timestamp --file <FILE> ....
|
||||
|
||||
|
||||
This log file will contain timestamps and this function will then normalize
|
||||
those packets to be relative to the first value timestamp that is found and
|
||||
show delta times between log lines and also keep track of how long it takes
|
||||
@@ -86,9 +105,9 @@ def parse_log_file(file, options):
|
||||
file = open(file)
|
||||
lines = file.read().splitlines()
|
||||
for line in lines:
|
||||
match = timestamp_regex.match (line)
|
||||
match = timestamp_regex.match(line)
|
||||
if match:
|
||||
curr_time = float (match.group(2))
|
||||
curr_time = float(match.group(2))
|
||||
delta = 0.0
|
||||
if base_time:
|
||||
delta = curr_time - last_time
|
||||
@@ -99,17 +118,17 @@ def parse_log_file(file, options):
|
||||
last_time = curr_time
|
||||
else:
|
||||
print line
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
parse_time_log_args (sys.argv[1:])
|
||||
parse_time_log_args(sys.argv[1:])
|
||||
|
||||
else:
|
||||
import lldb
|
||||
if lldb.debugger:
|
||||
if lldb.debugger:
|
||||
# This initializer is being run from LLDB in the embedded command interpreter
|
||||
# Add any commands contained in this module to LLDB
|
||||
lldb.debugger.HandleCommand('command script add -f delta.parse_time_log parse_time_log')
|
||||
lldb.debugger.HandleCommand(
|
||||
'command script add -f delta.parse_time_log parse_time_log')
|
||||
print 'The "parse_time_log" command is now installed and ready for use, type "parse_time_log --help" for more information'
|
||||
|
||||
@@ -1,64 +1,67 @@
|
||||
# This implements the "diagnose-nsstring" command, usually installed in the debug session like
|
||||
# command script import lldb.diagnose
|
||||
# it is used when NSString summary formatter fails to replicate the logic that went into LLDB making the
|
||||
# decisions it did and providing some useful context information that can be used for improving the formatter
|
||||
# decisions it did and providing some useful context information that can
|
||||
# be used for improving the formatter
|
||||
|
||||
import lldb
|
||||
|
||||
def read_memory(process,location,size):
|
||||
data = ""
|
||||
error = lldb.SBError()
|
||||
for x in range(0,size-1):
|
||||
byte = process.ReadUnsignedFromMemory(x+location,1,error)
|
||||
if error.fail:
|
||||
data = data + "err%s" % "" if x == size-2 else ":"
|
||||
else:
|
||||
try:
|
||||
data = data + "0x%x" % byte
|
||||
if byte == 0:
|
||||
data = data + "(\\0)"
|
||||
elif byte == 0xa:
|
||||
data = data + "(\\a)"
|
||||
elif byte == 0xb:
|
||||
data = data + "(\\b)"
|
||||
elif byte == 0xc:
|
||||
data = data + "(\\c)"
|
||||
elif byte == '\n':
|
||||
data = data + "(\\n)"
|
||||
else:
|
||||
data = data + "(%s)" % chr(byte)
|
||||
if x < size-2:
|
||||
data = data + ":"
|
||||
except Exception as e:
|
||||
print e
|
||||
return data
|
||||
|
||||
def diagnose_nsstring_Command_Impl(debugger,command,result,internal_dict):
|
||||
"""
|
||||
A command to diagnose the LLDB NSString data formatter
|
||||
invoke as
|
||||
(lldb) diagnose-nsstring <expr returning NSString>
|
||||
e.g.
|
||||
(lldb) diagnose-nsstring @"Hello world"
|
||||
"""
|
||||
target = debugger.GetSelectedTarget()
|
||||
process = target.GetProcess()
|
||||
thread = process.GetSelectedThread()
|
||||
frame = thread.GetSelectedFrame()
|
||||
if not target.IsValid() or not process.IsValid():
|
||||
return "unable to get target/process - cannot proceed"
|
||||
options = lldb.SBExpressionOptions()
|
||||
options.SetFetchDynamicValue()
|
||||
error = lldb.SBError()
|
||||
if frame.IsValid():
|
||||
nsstring = frame.EvaluateExpression(command,options)
|
||||
else:
|
||||
nsstring = target.EvaluateExpression(command,options)
|
||||
print >>result,str(nsstring)
|
||||
nsstring_address = nsstring.GetValueAsUnsigned(0)
|
||||
if nsstring_address == 0:
|
||||
return "unable to obtain the string - cannot proceed"
|
||||
expression = "\
|
||||
def read_memory(process, location, size):
|
||||
data = ""
|
||||
error = lldb.SBError()
|
||||
for x in range(0, size - 1):
|
||||
byte = process.ReadUnsignedFromMemory(x + location, 1, error)
|
||||
if error.fail:
|
||||
data = data + "err%s" % "" if x == size - 2 else ":"
|
||||
else:
|
||||
try:
|
||||
data = data + "0x%x" % byte
|
||||
if byte == 0:
|
||||
data = data + "(\\0)"
|
||||
elif byte == 0xa:
|
||||
data = data + "(\\a)"
|
||||
elif byte == 0xb:
|
||||
data = data + "(\\b)"
|
||||
elif byte == 0xc:
|
||||
data = data + "(\\c)"
|
||||
elif byte == '\n':
|
||||
data = data + "(\\n)"
|
||||
else:
|
||||
data = data + "(%s)" % chr(byte)
|
||||
if x < size - 2:
|
||||
data = data + ":"
|
||||
except Exception as e:
|
||||
print e
|
||||
return data
|
||||
|
||||
|
||||
def diagnose_nsstring_Command_Impl(debugger, command, result, internal_dict):
|
||||
"""
|
||||
A command to diagnose the LLDB NSString data formatter
|
||||
invoke as
|
||||
(lldb) diagnose-nsstring <expr returning NSString>
|
||||
e.g.
|
||||
(lldb) diagnose-nsstring @"Hello world"
|
||||
"""
|
||||
target = debugger.GetSelectedTarget()
|
||||
process = target.GetProcess()
|
||||
thread = process.GetSelectedThread()
|
||||
frame = thread.GetSelectedFrame()
|
||||
if not target.IsValid() or not process.IsValid():
|
||||
return "unable to get target/process - cannot proceed"
|
||||
options = lldb.SBExpressionOptions()
|
||||
options.SetFetchDynamicValue()
|
||||
error = lldb.SBError()
|
||||
if frame.IsValid():
|
||||
nsstring = frame.EvaluateExpression(command, options)
|
||||
else:
|
||||
nsstring = target.EvaluateExpression(command, options)
|
||||
print >>result, str(nsstring)
|
||||
nsstring_address = nsstring.GetValueAsUnsigned(0)
|
||||
if nsstring_address == 0:
|
||||
return "unable to obtain the string - cannot proceed"
|
||||
expression = "\
|
||||
struct $__lldb__notInlineMutable {\
|
||||
char* buffer;\
|
||||
signed long length;\
|
||||
@@ -97,75 +100,84 @@ struct $__lldb__CFString {\
|
||||
};\
|
||||
"
|
||||
|
||||
expression = expression + "*(($__lldb__CFString*) %d)" % nsstring_address
|
||||
# print expression
|
||||
dumped = target.EvaluateExpression(expression,options)
|
||||
print >>result, str(dumped)
|
||||
|
||||
little_endian = (target.byte_order == lldb.eByteOrderLittle)
|
||||
ptr_size = target.addr_size
|
||||
|
||||
info_bits = dumped.GetChildMemberWithName("_cfinfo").GetChildAtIndex(0 if little_endian else 3).GetValueAsUnsigned(0)
|
||||
is_mutable = (info_bits & 1) == 1
|
||||
is_inline = (info_bits & 0x60) == 0
|
||||
has_explicit_length = (info_bits & (1 | 4)) != 4
|
||||
is_unicode = (info_bits & 0x10) == 0x10
|
||||
is_special = (nsstring.GetDynamicValue(lldb.eDynamicCanRunTarget).GetTypeName() == "NSPathStore2")
|
||||
has_null = (info_bits & 8) == 8
|
||||
|
||||
print >>result,"\nInfo=%d\nMutable=%s\nInline=%s\nExplicit=%s\nUnicode=%s\nSpecial=%s\nNull=%s\n" % \
|
||||
(info_bits, "yes" if is_mutable else "no","yes" if is_inline else "no","yes" if has_explicit_length else "no","yes" if is_unicode else "no","yes" if is_special else "no","yes" if has_null else "no")
|
||||
expression = expression + "*(($__lldb__CFString*) %d)" % nsstring_address
|
||||
# print expression
|
||||
dumped = target.EvaluateExpression(expression, options)
|
||||
print >>result, str(dumped)
|
||||
|
||||
little_endian = (target.byte_order == lldb.eByteOrderLittle)
|
||||
ptr_size = target.addr_size
|
||||
|
||||
explicit_length_offset = 0
|
||||
if not has_null and has_explicit_length and not is_special:
|
||||
explicit_length_offset = 2*ptr_size
|
||||
if is_mutable and not is_inline:
|
||||
explicit_length_offset = explicit_length_offset + ptr_size
|
||||
elif is_inline:
|
||||
pass
|
||||
elif not is_inline and not is_mutable:
|
||||
explicit_length_offset = explicit_length_offset + ptr_size
|
||||
else:
|
||||
explicit_length_offset = 0
|
||||
info_bits = dumped.GetChildMemberWithName("_cfinfo").GetChildAtIndex(
|
||||
0 if little_endian else 3).GetValueAsUnsigned(0)
|
||||
is_mutable = (info_bits & 1) == 1
|
||||
is_inline = (info_bits & 0x60) == 0
|
||||
has_explicit_length = (info_bits & (1 | 4)) != 4
|
||||
is_unicode = (info_bits & 0x10) == 0x10
|
||||
is_special = (
|
||||
nsstring.GetDynamicValue(
|
||||
lldb.eDynamicCanRunTarget).GetTypeName() == "NSPathStore2")
|
||||
has_null = (info_bits & 8) == 8
|
||||
|
||||
if explicit_length_offset == 0:
|
||||
print >>result,"There is no explicit length marker - skipping this step\n"
|
||||
else:
|
||||
explicit_length_offset = nsstring_address + explicit_length_offset
|
||||
explicit_length = process.ReadUnsignedFromMemory(explicit_length_offset, 4, error)
|
||||
print >>result,"Explicit length location is at 0x%x - read value is %d\n" % (explicit_length_offset,explicit_length)
|
||||
print >>result, "\nInfo=%d\nMutable=%s\nInline=%s\nExplicit=%s\nUnicode=%s\nSpecial=%s\nNull=%s\n" % \
|
||||
(info_bits, "yes" if is_mutable else "no", "yes" if is_inline else "no", "yes" if has_explicit_length else "no", "yes" if is_unicode else "no", "yes" if is_special else "no", "yes" if has_null else "no")
|
||||
|
||||
explicit_length_offset = 0
|
||||
if not has_null and has_explicit_length and not is_special:
|
||||
explicit_length_offset = 2 * ptr_size
|
||||
if is_mutable and not is_inline:
|
||||
explicit_length_offset = explicit_length_offset + ptr_size
|
||||
elif is_inline:
|
||||
pass
|
||||
elif not is_inline and not is_mutable:
|
||||
explicit_length_offset = explicit_length_offset + ptr_size
|
||||
else:
|
||||
explicit_length_offset = 0
|
||||
|
||||
if explicit_length_offset == 0:
|
||||
print >>result, "There is no explicit length marker - skipping this step\n"
|
||||
else:
|
||||
explicit_length_offset = nsstring_address + explicit_length_offset
|
||||
explicit_length = process.ReadUnsignedFromMemory(
|
||||
explicit_length_offset, 4, error)
|
||||
print >>result, "Explicit length location is at 0x%x - read value is %d\n" % (
|
||||
explicit_length_offset, explicit_length)
|
||||
|
||||
if is_mutable:
|
||||
location = 2 * ptr_size + nsstring_address
|
||||
location = process.ReadPointerFromMemory(location, error)
|
||||
elif is_inline and has_explicit_length and not is_unicode and not is_special and not is_mutable:
|
||||
location = 3 * ptr_size + nsstring_address
|
||||
elif is_unicode:
|
||||
location = 2 * ptr_size + nsstring_address
|
||||
if is_inline:
|
||||
if not has_explicit_length:
|
||||
print >>result, "Unicode & Inline & !Explicit is a new combo - no formula for it"
|
||||
else:
|
||||
location += ptr_size
|
||||
else:
|
||||
location = process.ReadPointerFromMemory(location, error)
|
||||
elif is_special:
|
||||
location = nsstring_address + ptr_size + 4
|
||||
elif is_inline:
|
||||
location = 2 * ptr_size + nsstring_address
|
||||
if not has_explicit_length:
|
||||
location += 1
|
||||
else:
|
||||
location = 2 * ptr_size + nsstring_address
|
||||
location = process.ReadPointerFromMemory(location, error)
|
||||
print >>result, "Expected data location: 0x%x\n" % (location)
|
||||
print >>result, "1K of data around location: %s\n" % read_memory(
|
||||
process, location, 1024)
|
||||
print >>result, "5K of data around string pointer: %s\n" % read_memory(
|
||||
process, nsstring_address, 1024 * 5)
|
||||
|
||||
if is_mutable:
|
||||
location = 2 * ptr_size + nsstring_address
|
||||
location = process.ReadPointerFromMemory(location,error)
|
||||
elif is_inline and has_explicit_length and not is_unicode and not is_special and not is_mutable:
|
||||
location = 3 * ptr_size + nsstring_address
|
||||
elif is_unicode:
|
||||
location = 2 * ptr_size + nsstring_address
|
||||
if is_inline:
|
||||
if not has_explicit_length:
|
||||
print >>result,"Unicode & Inline & !Explicit is a new combo - no formula for it"
|
||||
else:
|
||||
location += ptr_size
|
||||
else:
|
||||
location = process.ReadPointerFromMemory(location,error)
|
||||
elif is_special:
|
||||
location = nsstring_address + ptr_size + 4
|
||||
elif is_inline:
|
||||
location = 2 * ptr_size + nsstring_address
|
||||
if not has_explicit_length:
|
||||
location += 1
|
||||
else:
|
||||
location = 2 * ptr_size + nsstring_address
|
||||
location = process.ReadPointerFromMemory(location,error)
|
||||
print >>result,"Expected data location: 0x%x\n" % (location)
|
||||
print >>result,"1K of data around location: %s\n" % read_memory(process,location,1024)
|
||||
print >>result,"5K of data around string pointer: %s\n" % read_memory(process,nsstring_address,1024*5)
|
||||
|
||||
def __lldb_init_module(debugger, internal_dict):
|
||||
debugger.HandleCommand("command script add -f %s.diagnose_nsstring_Command_Impl diagnose-nsstring" % __name__)
|
||||
print 'The "diagnose-nsstring" command has been installed, type "help diagnose-nsstring" for detailed help.'
|
||||
debugger.HandleCommand(
|
||||
"command script add -f %s.diagnose_nsstring_Command_Impl diagnose-nsstring" %
|
||||
__name__)
|
||||
print 'The "diagnose-nsstring" command has been installed, type "help diagnose-nsstring" for detailed help.'
|
||||
|
||||
__lldb_init_module(lldb.debugger,None)
|
||||
__lldb_init_module = None
|
||||
__lldb_init_module(lldb.debugger, None)
|
||||
__lldb_init_module = None
|
||||
|
||||
@@ -13,258 +13,301 @@ import shlex
|
||||
|
||||
# Print the frame number, pc, frame pointer, module UUID and function name
|
||||
# Returns the SBModule that contains the PC, if it could be found
|
||||
def backtrace_print_frame (target, frame_num, addr, fp):
|
||||
process = target.GetProcess()
|
||||
addr_for_printing = addr
|
||||
addr_width = process.GetAddressByteSize() * 2
|
||||
if frame_num > 0:
|
||||
addr = addr - 1
|
||||
|
||||
sbaddr = lldb.SBAddress()
|
||||
try:
|
||||
sbaddr.SetLoadAddress(addr, target)
|
||||
module_description = ""
|
||||
if sbaddr.GetModule():
|
||||
module_filename = ""
|
||||
module_uuid_str = sbaddr.GetModule().GetUUIDString()
|
||||
if module_uuid_str == None:
|
||||
module_uuid_str = ""
|
||||
if sbaddr.GetModule().GetFileSpec():
|
||||
module_filename = sbaddr.GetModule().GetFileSpec().GetFilename()
|
||||
if module_filename == None:
|
||||
module_filename = ""
|
||||
if module_uuid_str != "" or module_filename != "":
|
||||
module_description = '%s %s' % (module_filename, module_uuid_str)
|
||||
except Exception:
|
||||
print '%2d: pc==0x%-*x fp==0x%-*x' % (frame_num, addr_width, addr_for_printing, addr_width, fp)
|
||||
return
|
||||
|
||||
sym_ctx = target.ResolveSymbolContextForAddress(sbaddr, lldb.eSymbolContextEverything)
|
||||
if sym_ctx.IsValid() and sym_ctx.GetSymbol().IsValid():
|
||||
function_start = sym_ctx.GetSymbol().GetStartAddress().GetLoadAddress(target)
|
||||
offset = addr - function_start
|
||||
print '%2d: pc==0x%-*x fp==0x%-*x %s %s + %d' % (frame_num, addr_width, addr_for_printing, addr_width, fp, module_description, sym_ctx.GetSymbol().GetName(), offset)
|
||||
else:
|
||||
print '%2d: pc==0x%-*x fp==0x%-*x %s' % (frame_num, addr_width, addr_for_printing, addr_width, fp, module_description)
|
||||
return sbaddr.GetModule()
|
||||
def backtrace_print_frame(target, frame_num, addr, fp):
|
||||
process = target.GetProcess()
|
||||
addr_for_printing = addr
|
||||
addr_width = process.GetAddressByteSize() * 2
|
||||
if frame_num > 0:
|
||||
addr = addr - 1
|
||||
|
||||
sbaddr = lldb.SBAddress()
|
||||
try:
|
||||
sbaddr.SetLoadAddress(addr, target)
|
||||
module_description = ""
|
||||
if sbaddr.GetModule():
|
||||
module_filename = ""
|
||||
module_uuid_str = sbaddr.GetModule().GetUUIDString()
|
||||
if module_uuid_str is None:
|
||||
module_uuid_str = ""
|
||||
if sbaddr.GetModule().GetFileSpec():
|
||||
module_filename = sbaddr.GetModule().GetFileSpec().GetFilename()
|
||||
if module_filename is None:
|
||||
module_filename = ""
|
||||
if module_uuid_str != "" or module_filename != "":
|
||||
module_description = '%s %s' % (
|
||||
module_filename, module_uuid_str)
|
||||
except Exception:
|
||||
print '%2d: pc==0x%-*x fp==0x%-*x' % (frame_num, addr_width, addr_for_printing, addr_width, fp)
|
||||
return
|
||||
|
||||
sym_ctx = target.ResolveSymbolContextForAddress(
|
||||
sbaddr, lldb.eSymbolContextEverything)
|
||||
if sym_ctx.IsValid() and sym_ctx.GetSymbol().IsValid():
|
||||
function_start = sym_ctx.GetSymbol().GetStartAddress().GetLoadAddress(target)
|
||||
offset = addr - function_start
|
||||
print '%2d: pc==0x%-*x fp==0x%-*x %s %s + %d' % (frame_num, addr_width, addr_for_printing, addr_width, fp, module_description, sym_ctx.GetSymbol().GetName(), offset)
|
||||
else:
|
||||
print '%2d: pc==0x%-*x fp==0x%-*x %s' % (frame_num, addr_width, addr_for_printing, addr_width, fp, module_description)
|
||||
return sbaddr.GetModule()
|
||||
|
||||
# A simple stack walk algorithm that follows the frame chain.
|
||||
# Returns a two-element list; the first element is a list of modules
|
||||
# seen and the second element is a list of addresses seen during the backtrace.
|
||||
|
||||
|
||||
def simple_backtrace(debugger):
|
||||
target = debugger.GetSelectedTarget()
|
||||
process = target.GetProcess()
|
||||
cur_thread = process.GetSelectedThread()
|
||||
target = debugger.GetSelectedTarget()
|
||||
process = target.GetProcess()
|
||||
cur_thread = process.GetSelectedThread()
|
||||
|
||||
initial_fp = cur_thread.GetFrameAtIndex(0).GetFP()
|
||||
initial_fp = cur_thread.GetFrameAtIndex(0).GetFP()
|
||||
|
||||
# If the pseudoreg "fp" isn't recognized, on arm hardcode to r7 which is correct for Darwin programs.
|
||||
if initial_fp == lldb.LLDB_INVALID_ADDRESS and target.triple[0:3] == "arm":
|
||||
for reggroup in cur_thread.GetFrameAtIndex(1).registers:
|
||||
if reggroup.GetName() == "General Purpose Registers":
|
||||
for reg in reggroup:
|
||||
if reg.GetName() == "r7":
|
||||
initial_fp = int (reg.GetValue(), 16)
|
||||
# If the pseudoreg "fp" isn't recognized, on arm hardcode to r7 which is
|
||||
# correct for Darwin programs.
|
||||
if initial_fp == lldb.LLDB_INVALID_ADDRESS and target.triple[0:3] == "arm":
|
||||
for reggroup in cur_thread.GetFrameAtIndex(1).registers:
|
||||
if reggroup.GetName() == "General Purpose Registers":
|
||||
for reg in reggroup:
|
||||
if reg.GetName() == "r7":
|
||||
initial_fp = int(reg.GetValue(), 16)
|
||||
|
||||
module_list = []
|
||||
address_list = [cur_thread.GetFrameAtIndex(0).GetPC()]
|
||||
this_module = backtrace_print_frame (target, 0, cur_thread.GetFrameAtIndex(0).GetPC(), initial_fp)
|
||||
print_stack_frame (process, initial_fp)
|
||||
print ""
|
||||
if this_module != None:
|
||||
module_list.append (this_module)
|
||||
if cur_thread.GetNumFrames() < 2:
|
||||
module_list = []
|
||||
address_list = [cur_thread.GetFrameAtIndex(0).GetPC()]
|
||||
this_module = backtrace_print_frame(
|
||||
target, 0, cur_thread.GetFrameAtIndex(0).GetPC(), initial_fp)
|
||||
print_stack_frame(process, initial_fp)
|
||||
print ""
|
||||
if this_module is not None:
|
||||
module_list.append(this_module)
|
||||
if cur_thread.GetNumFrames() < 2:
|
||||
return [module_list, address_list]
|
||||
|
||||
cur_fp = process.ReadPointerFromMemory(initial_fp, lldb.SBError())
|
||||
cur_pc = process.ReadPointerFromMemory(
|
||||
initial_fp + process.GetAddressByteSize(), lldb.SBError())
|
||||
|
||||
frame_num = 1
|
||||
|
||||
while cur_pc != 0 and cur_fp != 0 and cur_pc != lldb.LLDB_INVALID_ADDRESS and cur_fp != lldb.LLDB_INVALID_ADDRESS:
|
||||
address_list.append(cur_pc)
|
||||
this_module = backtrace_print_frame(target, frame_num, cur_pc, cur_fp)
|
||||
print_stack_frame(process, cur_fp)
|
||||
print ""
|
||||
if this_module is not None:
|
||||
module_list.append(this_module)
|
||||
frame_num = frame_num + 1
|
||||
next_pc = 0
|
||||
next_fp = 0
|
||||
if target.triple[
|
||||
0:6] == "x86_64" or target.triple[
|
||||
0:4] == "i386" or target.triple[
|
||||
0:3] == "arm":
|
||||
error = lldb.SBError()
|
||||
next_pc = process.ReadPointerFromMemory(
|
||||
cur_fp + process.GetAddressByteSize(), error)
|
||||
if not error.Success():
|
||||
next_pc = 0
|
||||
next_fp = process.ReadPointerFromMemory(cur_fp, error)
|
||||
if not error.Success():
|
||||
next_fp = 0
|
||||
# Clear the 0th bit for arm frames - this indicates it is a thumb frame
|
||||
if target.triple[0:3] == "arm" and (next_pc & 1) == 1:
|
||||
next_pc = next_pc & ~1
|
||||
cur_pc = next_pc
|
||||
cur_fp = next_fp
|
||||
this_module = backtrace_print_frame(target, frame_num, cur_pc, cur_fp)
|
||||
print_stack_frame(process, cur_fp)
|
||||
print ""
|
||||
if this_module is not None:
|
||||
module_list.append(this_module)
|
||||
return [module_list, address_list]
|
||||
|
||||
cur_fp = process.ReadPointerFromMemory (initial_fp, lldb.SBError())
|
||||
cur_pc = process.ReadPointerFromMemory (initial_fp + process.GetAddressByteSize(), lldb.SBError())
|
||||
|
||||
frame_num = 1
|
||||
|
||||
while cur_pc != 0 and cur_fp != 0 and cur_pc != lldb.LLDB_INVALID_ADDRESS and cur_fp != lldb.LLDB_INVALID_ADDRESS:
|
||||
address_list.append (cur_pc)
|
||||
this_module = backtrace_print_frame (target, frame_num, cur_pc, cur_fp)
|
||||
print_stack_frame (process, cur_fp)
|
||||
print ""
|
||||
if this_module != None:
|
||||
module_list.append (this_module)
|
||||
frame_num = frame_num + 1
|
||||
next_pc = 0
|
||||
next_fp = 0
|
||||
if target.triple[0:6] == "x86_64" or target.triple[0:4] == "i386" or target.triple[0:3] == "arm":
|
||||
error = lldb.SBError()
|
||||
next_pc = process.ReadPointerFromMemory(cur_fp + process.GetAddressByteSize(), error)
|
||||
if not error.Success():
|
||||
next_pc = 0
|
||||
next_fp = process.ReadPointerFromMemory(cur_fp, error)
|
||||
if not error.Success():
|
||||
next_fp = 0
|
||||
# Clear the 0th bit for arm frames - this indicates it is a thumb frame
|
||||
if target.triple[0:3] == "arm" and (next_pc & 1) == 1:
|
||||
next_pc = next_pc & ~1
|
||||
cur_pc = next_pc
|
||||
cur_fp = next_fp
|
||||
this_module = backtrace_print_frame (target, frame_num, cur_pc, cur_fp)
|
||||
print_stack_frame (process, cur_fp)
|
||||
print ""
|
||||
if this_module != None:
|
||||
module_list.append (this_module)
|
||||
return [module_list, address_list]
|
||||
|
||||
def print_stack_frame(process, fp):
|
||||
if fp == 0 or fp == lldb.LLDB_INVALID_ADDRESS or fp == 1:
|
||||
return
|
||||
addr_size = process.GetAddressByteSize()
|
||||
addr = fp - (2 * addr_size)
|
||||
i = 0
|
||||
outline = "Stack frame from $fp-%d: " % (2 * addr_size)
|
||||
error = lldb.SBError()
|
||||
try:
|
||||
while i < 5 and error.Success():
|
||||
address = process.ReadPointerFromMemory(addr + (i * addr_size), error)
|
||||
outline += " 0x%x" % address
|
||||
i += 1
|
||||
print outline
|
||||
except Exception:
|
||||
return
|
||||
if fp == 0 or fp == lldb.LLDB_INVALID_ADDRESS or fp == 1:
|
||||
return
|
||||
addr_size = process.GetAddressByteSize()
|
||||
addr = fp - (2 * addr_size)
|
||||
i = 0
|
||||
outline = "Stack frame from $fp-%d: " % (2 * addr_size)
|
||||
error = lldb.SBError()
|
||||
try:
|
||||
while i < 5 and error.Success():
|
||||
address = process.ReadPointerFromMemory(
|
||||
addr + (i * addr_size), error)
|
||||
outline += " 0x%x" % address
|
||||
i += 1
|
||||
print outline
|
||||
except Exception:
|
||||
return
|
||||
|
||||
|
||||
def diagnose_unwind(debugger, command, result, dict):
|
||||
"""
|
||||
Gather diagnostic information to help debug incorrect unwind (backtrace)
|
||||
behavior in lldb. When there is a backtrace that doesn't look
|
||||
correct, run this command with the correct thread selected and a
|
||||
large amount of diagnostic information will be printed, it is likely
|
||||
to be helpful when reporting the problem.
|
||||
"""
|
||||
"""
|
||||
Gather diagnostic information to help debug incorrect unwind (backtrace)
|
||||
behavior in lldb. When there is a backtrace that doesn't look
|
||||
correct, run this command with the correct thread selected and a
|
||||
large amount of diagnostic information will be printed, it is likely
|
||||
to be helpful when reporting the problem.
|
||||
"""
|
||||
|
||||
command_args = shlex.split(command)
|
||||
parser = create_diagnose_unwind_options()
|
||||
try:
|
||||
(options, args) = parser.parse_args(command_args)
|
||||
except:
|
||||
return
|
||||
target = debugger.GetSelectedTarget()
|
||||
if target:
|
||||
process = target.GetProcess()
|
||||
if process:
|
||||
thread = process.GetSelectedThread()
|
||||
if thread:
|
||||
lldb_versions_match = re.search(r'[lL][lL][dD][bB]-(\d+)([.](\d+))?([.](\d+))?', debugger.GetVersionString())
|
||||
lldb_version = 0
|
||||
lldb_minor = 0
|
||||
if len(lldb_versions_match.groups()) >= 1 and lldb_versions_match.groups()[0]:
|
||||
lldb_major = int(lldb_versions_match.groups()[0])
|
||||
if len(lldb_versions_match.groups()) >= 5 and lldb_versions_match.groups()[4]:
|
||||
lldb_minor = int(lldb_versions_match.groups()[4])
|
||||
command_args = shlex.split(command)
|
||||
parser = create_diagnose_unwind_options()
|
||||
try:
|
||||
(options, args) = parser.parse_args(command_args)
|
||||
except:
|
||||
return
|
||||
target = debugger.GetSelectedTarget()
|
||||
if target:
|
||||
process = target.GetProcess()
|
||||
if process:
|
||||
thread = process.GetSelectedThread()
|
||||
if thread:
|
||||
lldb_versions_match = re.search(
|
||||
r'[lL][lL][dD][bB]-(\d+)([.](\d+))?([.](\d+))?',
|
||||
debugger.GetVersionString())
|
||||
lldb_version = 0
|
||||
lldb_minor = 0
|
||||
if len(lldb_versions_match.groups()
|
||||
) >= 1 and lldb_versions_match.groups()[0]:
|
||||
lldb_major = int(lldb_versions_match.groups()[0])
|
||||
if len(lldb_versions_match.groups()
|
||||
) >= 5 and lldb_versions_match.groups()[4]:
|
||||
lldb_minor = int(lldb_versions_match.groups()[4])
|
||||
|
||||
modules_seen = []
|
||||
addresses_seen = []
|
||||
modules_seen = []
|
||||
addresses_seen = []
|
||||
|
||||
print 'LLDB version %s' % debugger.GetVersionString()
|
||||
print 'Unwind diagnostics for thread %d' % thread.GetIndexID()
|
||||
print ""
|
||||
print "============================================================================================="
|
||||
print ""
|
||||
print "OS plugin setting:"
|
||||
debugger.HandleCommand("settings show target.process.python-os-plugin-path")
|
||||
print ""
|
||||
print "Live register context:"
|
||||
thread.SetSelectedFrame(0)
|
||||
debugger.HandleCommand("register read")
|
||||
print ""
|
||||
print "============================================================================================="
|
||||
print ""
|
||||
print "lldb's unwind algorithm:"
|
||||
print ""
|
||||
frame_num = 0
|
||||
for frame in thread.frames:
|
||||
if not frame.IsInlined():
|
||||
this_module = backtrace_print_frame (target, frame_num, frame.GetPC(), frame.GetFP())
|
||||
print_stack_frame (process, frame.GetFP())
|
||||
print ""
|
||||
if this_module != None:
|
||||
modules_seen.append (this_module)
|
||||
addresses_seen.append (frame.GetPC())
|
||||
frame_num = frame_num + 1
|
||||
print ""
|
||||
print "============================================================================================="
|
||||
print ""
|
||||
print "Simple stack walk algorithm:"
|
||||
print ""
|
||||
(module_list, address_list) = simple_backtrace(debugger)
|
||||
if module_list and module_list != None:
|
||||
modules_seen += module_list
|
||||
if address_list and address_list != None:
|
||||
addresses_seen = set(addresses_seen)
|
||||
addresses_seen.update(set(address_list))
|
||||
print 'LLDB version %s' % debugger.GetVersionString()
|
||||
print 'Unwind diagnostics for thread %d' % thread.GetIndexID()
|
||||
print ""
|
||||
print "============================================================================================="
|
||||
print ""
|
||||
print "OS plugin setting:"
|
||||
debugger.HandleCommand(
|
||||
"settings show target.process.python-os-plugin-path")
|
||||
print ""
|
||||
print "Live register context:"
|
||||
thread.SetSelectedFrame(0)
|
||||
debugger.HandleCommand("register read")
|
||||
print ""
|
||||
print "============================================================================================="
|
||||
print ""
|
||||
print "lldb's unwind algorithm:"
|
||||
print ""
|
||||
frame_num = 0
|
||||
for frame in thread.frames:
|
||||
if not frame.IsInlined():
|
||||
this_module = backtrace_print_frame(
|
||||
target, frame_num, frame.GetPC(), frame.GetFP())
|
||||
print_stack_frame(process, frame.GetFP())
|
||||
print ""
|
||||
if this_module is not None:
|
||||
modules_seen.append(this_module)
|
||||
addresses_seen.append(frame.GetPC())
|
||||
frame_num = frame_num + 1
|
||||
print ""
|
||||
print "============================================================================================="
|
||||
print ""
|
||||
print "Simple stack walk algorithm:"
|
||||
print ""
|
||||
(module_list, address_list) = simple_backtrace(debugger)
|
||||
if module_list and module_list is not None:
|
||||
modules_seen += module_list
|
||||
if address_list and address_list is not None:
|
||||
addresses_seen = set(addresses_seen)
|
||||
addresses_seen.update(set(address_list))
|
||||
|
||||
print ""
|
||||
print "============================================================================================="
|
||||
print ""
|
||||
print "Modules seen in stack walks:"
|
||||
print ""
|
||||
modules_already_seen = set()
|
||||
for module in modules_seen:
|
||||
if module != None and module.GetFileSpec().GetFilename() != None:
|
||||
if not module.GetFileSpec().GetFilename() in modules_already_seen:
|
||||
debugger.HandleCommand('image list %s' % module.GetFileSpec().GetFilename())
|
||||
modules_already_seen.add(module.GetFileSpec().GetFilename())
|
||||
print ""
|
||||
print "============================================================================================="
|
||||
print ""
|
||||
print "Modules seen in stack walks:"
|
||||
print ""
|
||||
modules_already_seen = set()
|
||||
for module in modules_seen:
|
||||
if module is not None and module.GetFileSpec().GetFilename() is not None:
|
||||
if not module.GetFileSpec().GetFilename() in modules_already_seen:
|
||||
debugger.HandleCommand(
|
||||
'image list %s' %
|
||||
module.GetFileSpec().GetFilename())
|
||||
modules_already_seen.add(
|
||||
module.GetFileSpec().GetFilename())
|
||||
|
||||
print ""
|
||||
print "============================================================================================="
|
||||
print ""
|
||||
print "Disassembly ofaddresses seen in stack walks:"
|
||||
print ""
|
||||
additional_addresses_to_disassemble = addresses_seen
|
||||
for frame in thread.frames:
|
||||
if not frame.IsInlined():
|
||||
print "--------------------------------------------------------------------------------------"
|
||||
print ""
|
||||
print "Disassembly of %s, frame %d, address 0x%x" % (frame.GetFunctionName(), frame.GetFrameID(), frame.GetPC())
|
||||
print ""
|
||||
if target.triple[0:6] == "x86_64" or target.triple[0:4] == "i386":
|
||||
debugger.HandleCommand('disassemble -F att -a 0x%x' % frame.GetPC())
|
||||
else:
|
||||
debugger.HandleCommand('disassemble -a 0x%x' % frame.GetPC())
|
||||
if frame.GetPC() in additional_addresses_to_disassemble:
|
||||
additional_addresses_to_disassemble.remove (frame.GetPC())
|
||||
print ""
|
||||
print "============================================================================================="
|
||||
print ""
|
||||
print "Disassembly ofaddresses seen in stack walks:"
|
||||
print ""
|
||||
additional_addresses_to_disassemble = addresses_seen
|
||||
for frame in thread.frames:
|
||||
if not frame.IsInlined():
|
||||
print "--------------------------------------------------------------------------------------"
|
||||
print ""
|
||||
print "Disassembly of %s, frame %d, address 0x%x" % (frame.GetFunctionName(), frame.GetFrameID(), frame.GetPC())
|
||||
print ""
|
||||
if target.triple[
|
||||
0:6] == "x86_64" or target.triple[
|
||||
0:4] == "i386":
|
||||
debugger.HandleCommand(
|
||||
'disassemble -F att -a 0x%x' % frame.GetPC())
|
||||
else:
|
||||
debugger.HandleCommand(
|
||||
'disassemble -a 0x%x' %
|
||||
frame.GetPC())
|
||||
if frame.GetPC() in additional_addresses_to_disassemble:
|
||||
additional_addresses_to_disassemble.remove(
|
||||
frame.GetPC())
|
||||
|
||||
for address in list(additional_addresses_to_disassemble):
|
||||
print "--------------------------------------------------------------------------------------"
|
||||
print ""
|
||||
print "Disassembly of 0x%x" % address
|
||||
print ""
|
||||
if target.triple[0:6] == "x86_64" or target.triple[0:4] == "i386":
|
||||
debugger.HandleCommand('disassemble -F att -a 0x%x' % address)
|
||||
else:
|
||||
debugger.HandleCommand('disassemble -a 0x%x' % address)
|
||||
for address in list(additional_addresses_to_disassemble):
|
||||
print "--------------------------------------------------------------------------------------"
|
||||
print ""
|
||||
print "Disassembly of 0x%x" % address
|
||||
print ""
|
||||
if target.triple[
|
||||
0:6] == "x86_64" or target.triple[
|
||||
0:4] == "i386":
|
||||
debugger.HandleCommand(
|
||||
'disassemble -F att -a 0x%x' % address)
|
||||
else:
|
||||
debugger.HandleCommand('disassemble -a 0x%x' % address)
|
||||
|
||||
print ""
|
||||
print "============================================================================================="
|
||||
print ""
|
||||
additional_addresses_to_show_unwind = addresses_seen
|
||||
for frame in thread.frames:
|
||||
if not frame.IsInlined():
|
||||
print "--------------------------------------------------------------------------------------"
|
||||
print ""
|
||||
print "Unwind instructions for %s, frame %d" % (frame.GetFunctionName(), frame.GetFrameID())
|
||||
print ""
|
||||
debugger.HandleCommand('image show-unwind -a "0x%x"' % frame.GetPC())
|
||||
if frame.GetPC() in additional_addresses_to_show_unwind:
|
||||
additional_addresses_to_show_unwind.remove (frame.GetPC())
|
||||
print ""
|
||||
print "============================================================================================="
|
||||
print ""
|
||||
additional_addresses_to_show_unwind = addresses_seen
|
||||
for frame in thread.frames:
|
||||
if not frame.IsInlined():
|
||||
print "--------------------------------------------------------------------------------------"
|
||||
print ""
|
||||
print "Unwind instructions for %s, frame %d" % (frame.GetFunctionName(), frame.GetFrameID())
|
||||
print ""
|
||||
debugger.HandleCommand(
|
||||
'image show-unwind -a "0x%x"' % frame.GetPC())
|
||||
if frame.GetPC() in additional_addresses_to_show_unwind:
|
||||
additional_addresses_to_show_unwind.remove(
|
||||
frame.GetPC())
|
||||
|
||||
for address in list(additional_addresses_to_show_unwind):
|
||||
print "--------------------------------------------------------------------------------------"
|
||||
print ""
|
||||
print "Unwind instructions for 0x%x" % address
|
||||
print ""
|
||||
debugger.HandleCommand(
|
||||
'image show-unwind -a "0x%x"' % address)
|
||||
|
||||
for address in list(additional_addresses_to_show_unwind):
|
||||
print "--------------------------------------------------------------------------------------"
|
||||
print ""
|
||||
print "Unwind instructions for 0x%x" % address
|
||||
print ""
|
||||
debugger.HandleCommand('image show-unwind -a "0x%x"' % address)
|
||||
|
||||
def create_diagnose_unwind_options():
|
||||
usage = "usage: %prog"
|
||||
description='''Print diagnostic information about a thread backtrace which will help to debug unwind problems'''
|
||||
parser = optparse.OptionParser(description=description, prog='diagnose_unwind',usage=usage)
|
||||
return parser
|
||||
usage = "usage: %prog"
|
||||
description = '''Print diagnostic information about a thread backtrace which will help to debug unwind problems'''
|
||||
parser = optparse.OptionParser(
|
||||
description=description,
|
||||
prog='diagnose_unwind',
|
||||
usage=usage)
|
||||
return parser
|
||||
|
||||
lldb.debugger.HandleCommand('command script add -f %s.diagnose_unwind diagnose-unwind' % __name__)
|
||||
lldb.debugger.HandleCommand(
|
||||
'command script add -f %s.diagnose_unwind diagnose-unwind' %
|
||||
__name__)
|
||||
print 'The "diagnose-unwind" command has been installed, type "help diagnose-unwind" for detailed help.'
|
||||
|
||||
@@ -1,27 +1,28 @@
|
||||
|
||||
|
||||
class LookupDictionary(dict):
|
||||
"""
|
||||
a dictionary which can lookup value by key, or keys by value
|
||||
"""
|
||||
|
||||
def __init__(self, items=[]):
|
||||
"""items can be a list of pair_lists or a dictionary"""
|
||||
dict.__init__(self, items)
|
||||
|
||||
def get_keys_for_value(self, value, fail_value = None):
|
||||
|
||||
def get_keys_for_value(self, value, fail_value=None):
|
||||
"""find the key(s) as a list given a value"""
|
||||
list_result = [item[0] for item in self.items() if item[1] == value]
|
||||
if len(list_result) > 0:
|
||||
return list_result
|
||||
return fail_value
|
||||
|
||||
def get_first_key_for_value(self, value, fail_value = None):
|
||||
|
||||
def get_first_key_for_value(self, value, fail_value=None):
|
||||
"""return the first key of this dictionary given the value"""
|
||||
list_result = [item[0] for item in self.items() if item[1] == value]
|
||||
if len(list_result) > 0:
|
||||
return list_result[0]
|
||||
return fail_value
|
||||
|
||||
def get_value(self, key, fail_value = None):
|
||||
def get_value(self, key, fail_value=None):
|
||||
"""find the value given a key"""
|
||||
if key in self:
|
||||
return self[key]
|
||||
@@ -29,12 +30,12 @@ class LookupDictionary(dict):
|
||||
|
||||
|
||||
class Enum(LookupDictionary):
|
||||
|
||||
|
||||
def __init__(self, initial_value=0, items=[]):
|
||||
"""items can be a list of pair_lists or a dictionary"""
|
||||
LookupDictionary.__init__(self, items)
|
||||
self.value = initial_value
|
||||
|
||||
|
||||
def set_value(self, v):
|
||||
v_typename = typeof(v).__name__
|
||||
if v_typename == 'str':
|
||||
@@ -44,18 +45,18 @@ class Enum(LookupDictionary):
|
||||
v = 0
|
||||
else:
|
||||
self.value = v
|
||||
|
||||
|
||||
def get_enum_value(self):
|
||||
return self.value
|
||||
|
||||
|
||||
def get_enum_name(self):
|
||||
return self.__str__()
|
||||
|
||||
def __str__(self):
|
||||
s = self.get_first_key_for_value (self.value, None)
|
||||
if s == None:
|
||||
s = self.get_first_key_for_value(self.value, None)
|
||||
if s is None:
|
||||
s = "%#8.8x" % self.value
|
||||
return s
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
return self.__str__()
|
||||
return self.__str__()
|
||||
|
||||
@@ -1,40 +1,82 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import argparse, datetime, re, subprocess, sys, time
|
||||
import argparse
|
||||
import datetime
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
|
||||
parser = argparse.ArgumentParser(description="Run an exhaustive test of the LLDB disassembler for a specific architecture.")
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Run an exhaustive test of the LLDB disassembler for a specific architecture.")
|
||||
|
||||
parser.add_argument('--arch', required=True, action='store', help='The architecture whose disassembler is to be tested')
|
||||
parser.add_argument('--bytes', required=True, action='store', type=int, help='The byte width of instructions for that architecture')
|
||||
parser.add_argument('--random', required=False, action='store_true', help='Enables non-sequential testing')
|
||||
parser.add_argument('--start', required=False, action='store', type=int, help='The first instruction value to test')
|
||||
parser.add_argument('--skip', required=False, action='store', type=int, help='The interval between instructions to test')
|
||||
parser.add_argument('--log', required=False, action='store', help='A log file to write the most recent instruction being tested')
|
||||
parser.add_argument('--time', required=False, action='store_true', help='Every 100,000 instructions, print an ETA to standard out')
|
||||
parser.add_argument('--lldb', required=False, action='store', help='The path to LLDB.framework, if LLDB should be overridden')
|
||||
parser.add_argument(
|
||||
'--arch',
|
||||
required=True,
|
||||
action='store',
|
||||
help='The architecture whose disassembler is to be tested')
|
||||
parser.add_argument(
|
||||
'--bytes',
|
||||
required=True,
|
||||
action='store',
|
||||
type=int,
|
||||
help='The byte width of instructions for that architecture')
|
||||
parser.add_argument(
|
||||
'--random',
|
||||
required=False,
|
||||
action='store_true',
|
||||
help='Enables non-sequential testing')
|
||||
parser.add_argument(
|
||||
'--start',
|
||||
required=False,
|
||||
action='store',
|
||||
type=int,
|
||||
help='The first instruction value to test')
|
||||
parser.add_argument(
|
||||
'--skip',
|
||||
required=False,
|
||||
action='store',
|
||||
type=int,
|
||||
help='The interval between instructions to test')
|
||||
parser.add_argument(
|
||||
'--log',
|
||||
required=False,
|
||||
action='store',
|
||||
help='A log file to write the most recent instruction being tested')
|
||||
parser.add_argument(
|
||||
'--time',
|
||||
required=False,
|
||||
action='store_true',
|
||||
help='Every 100,000 instructions, print an ETA to standard out')
|
||||
parser.add_argument(
|
||||
'--lldb',
|
||||
required=False,
|
||||
action='store',
|
||||
help='The path to LLDB.framework, if LLDB should be overridden')
|
||||
|
||||
arguments = sys.argv[1:]
|
||||
|
||||
arg_ns = parser.parse_args(arguments)
|
||||
|
||||
|
||||
def AddLLDBToSysPathOnMacOSX():
|
||||
def GetLLDBFrameworkPath():
|
||||
lldb_path = subprocess.check_output(["xcrun", "-find", "lldb"])
|
||||
re_result = re.match("(.*)/Developer/usr/bin/lldb", lldb_path)
|
||||
if re_result == None:
|
||||
if re_result is None:
|
||||
return None
|
||||
xcode_contents_path = re_result.group(1)
|
||||
return xcode_contents_path + "/SharedFrameworks/LLDB.framework"
|
||||
|
||||
|
||||
lldb_framework_path = GetLLDBFrameworkPath()
|
||||
|
||||
if lldb_framework_path == None:
|
||||
|
||||
if lldb_framework_path is None:
|
||||
print "Couldn't find LLDB.framework"
|
||||
sys.exit(-1)
|
||||
|
||||
|
||||
sys.path.append(lldb_framework_path + "/Resources/Python")
|
||||
|
||||
if arg_ns.lldb == None:
|
||||
if arg_ns.lldb is None:
|
||||
AddLLDBToSysPathOnMacOSX()
|
||||
else:
|
||||
sys.path.append(arg_ns.lldb + "/Resources/Python")
|
||||
@@ -53,16 +95,20 @@ if target.IsValid() == False:
|
||||
print "Couldn't create an SBTarget for architecture " + arg_ns.arch
|
||||
sys.exit(-1)
|
||||
|
||||
|
||||
def ResetLogFile(log_file):
|
||||
if log_file != sys.stdout:
|
||||
log_file.seek(0)
|
||||
|
||||
|
||||
def PrintByteArray(log_file, byte_array):
|
||||
for byte in byte_array:
|
||||
print >>log_file, hex(byte) + " ",
|
||||
print >>log_file
|
||||
|
||||
|
||||
|
||||
class SequentialInstructionProvider:
|
||||
|
||||
def __init__(self, byte_width, log_file, start=0, skip=1):
|
||||
self.m_byte_width = byte_width
|
||||
self.m_log_file = log_file
|
||||
@@ -70,70 +116,83 @@ class SequentialInstructionProvider:
|
||||
self.m_skip = skip
|
||||
self.m_value = start
|
||||
self.m_last = (1 << (byte_width * 8)) - 1
|
||||
|
||||
def PrintCurrentState(self, ret):
|
||||
ResetLogFile(self.m_log_file)
|
||||
print >>self.m_log_file, self.m_value
|
||||
PrintByteArray(self.m_log_file, ret)
|
||||
|
||||
def GetNextInstruction(self):
|
||||
if self.m_value > self.m_last:
|
||||
return None
|
||||
ret = bytearray(self.m_byte_width)
|
||||
for i in range(self.m_byte_width):
|
||||
ret[self.m_byte_width - (i + 1)] = (self.m_value >> (i * 8)) & 255
|
||||
ret[self.m_byte_width - (i + 1)] = (self.m_value >> (i * 8)) & 255
|
||||
self.PrintCurrentState(ret)
|
||||
self.m_value += self.m_skip
|
||||
return ret
|
||||
|
||||
def GetNumInstructions(self):
|
||||
return (self.m_last - self.m_start) / self.m_skip
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
||||
def next(self):
|
||||
ret = self.GetNextInstruction()
|
||||
if ret == None:
|
||||
if ret is None:
|
||||
raise StopIteration
|
||||
return ret
|
||||
|
||||
|
||||
class RandomInstructionProvider:
|
||||
|
||||
def __init__(self, byte_width, log_file):
|
||||
self.m_byte_width = byte_width
|
||||
self.m_log_file = log_file
|
||||
self.m_random_file = open("/dev/random", 'r')
|
||||
|
||||
def PrintCurrentState(self, ret):
|
||||
ResetLogFile(self.m_log_file)
|
||||
PrintByteArray(self.m_log_file, ret)
|
||||
|
||||
def GetNextInstruction(self):
|
||||
ret = bytearray(self.m_byte_width)
|
||||
for i in range(self.m_byte_width):
|
||||
ret[i] = self.m_random_file.read(1)
|
||||
self.PrintCurrentState(ret)
|
||||
return ret
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
||||
def next(self):
|
||||
ret = self.GetNextInstruction()
|
||||
if ret == None:
|
||||
if ret is None:
|
||||
raise StopIteration
|
||||
return ret
|
||||
|
||||
log_file = None
|
||||
|
||||
|
||||
def GetProviderWithArguments(args):
|
||||
global log_file
|
||||
if args.log != None:
|
||||
if args.log is not None:
|
||||
log_file = open(args.log, 'w')
|
||||
else:
|
||||
log_file = sys.stdout
|
||||
instruction_provider = None
|
||||
if args.random == True:
|
||||
if args.random:
|
||||
instruction_provider = RandomInstructionProvider(args.bytes, log_file)
|
||||
else:
|
||||
start = 0
|
||||
skip = 1
|
||||
if args.start != None:
|
||||
if args.start is not None:
|
||||
start = args.start
|
||||
if args.skip != None:
|
||||
if args.skip is not None:
|
||||
skip = args.skip
|
||||
instruction_provider = SequentialInstructionProvider(args.bytes, log_file, start, skip)
|
||||
instruction_provider = SequentialInstructionProvider(
|
||||
args.bytes, log_file, start, skip)
|
||||
return instruction_provider
|
||||
|
||||
instruction_provider = GetProviderWithArguments(arg_ns)
|
||||
@@ -149,10 +208,13 @@ if actually_time:
|
||||
|
||||
for inst_bytes in instruction_provider:
|
||||
if actually_time:
|
||||
if (num_instructions_logged != 0) and (num_instructions_logged % 100000 == 0):
|
||||
if (num_instructions_logged != 0) and (
|
||||
num_instructions_logged % 100000 == 0):
|
||||
curr_time = time.time()
|
||||
elapsed_time = curr_time - start_time
|
||||
remaining_time = float(total_num_instructions - num_instructions_logged) * (float(elapsed_time) / float(num_instructions_logged))
|
||||
remaining_time = float(
|
||||
total_num_instructions - num_instructions_logged) * (
|
||||
float(elapsed_time) / float(num_instructions_logged))
|
||||
print str(datetime.timedelta(seconds=remaining_time))
|
||||
num_instructions_logged = num_instructions_logged + 1
|
||||
inst_list = target.GetInstructions(fake_address, inst_bytes)
|
||||
|
||||
@@ -12,10 +12,12 @@ import lldb
|
||||
import os
|
||||
import sys
|
||||
|
||||
def disassemble_instructions (insts):
|
||||
|
||||
def disassemble_instructions(insts):
|
||||
for i in insts:
|
||||
print i
|
||||
|
||||
|
||||
def usage():
|
||||
print "Usage: disasm.py [-n name] executable-image"
|
||||
print " By default, it breaks at and disassembles the 'main' function."
|
||||
@@ -36,63 +38,69 @@ else:
|
||||
# Create a new debugger instance
|
||||
debugger = lldb.SBDebugger.Create()
|
||||
|
||||
# When we step or continue, don't return from the function until the process
|
||||
# When we step or continue, don't return from the function until the process
|
||||
# stops. We do this by setting the async mode to false.
|
||||
debugger.SetAsync (False)
|
||||
debugger.SetAsync(False)
|
||||
|
||||
# Create a target from a file and arch
|
||||
print "Creating a target for '%s'" % exe
|
||||
|
||||
target = debugger.CreateTargetWithFileAndArch (exe, lldb.LLDB_ARCH_DEFAULT)
|
||||
target = debugger.CreateTargetWithFileAndArch(exe, lldb.LLDB_ARCH_DEFAULT)
|
||||
|
||||
if target:
|
||||
# If the target is valid set a breakpoint at main
|
||||
main_bp = target.BreakpointCreateByName (fname, target.GetExecutable().GetFilename());
|
||||
main_bp = target.BreakpointCreateByName(
|
||||
fname, target.GetExecutable().GetFilename())
|
||||
|
||||
print main_bp
|
||||
|
||||
# Launch the process. Since we specified synchronous mode, we won't return
|
||||
# from this function until we hit the breakpoint at main
|
||||
process = target.LaunchSimple (None, None, os.getcwd())
|
||||
|
||||
process = target.LaunchSimple(None, None, os.getcwd())
|
||||
|
||||
# Make sure the launch went ok
|
||||
if process:
|
||||
# Print some simple process info
|
||||
state = process.GetState ()
|
||||
state = process.GetState()
|
||||
print process
|
||||
if state == lldb.eStateStopped:
|
||||
# Get the first thread
|
||||
thread = process.GetThreadAtIndex (0)
|
||||
thread = process.GetThreadAtIndex(0)
|
||||
if thread:
|
||||
# Print some simple thread info
|
||||
print thread
|
||||
# Get the first frame
|
||||
frame = thread.GetFrameAtIndex (0)
|
||||
frame = thread.GetFrameAtIndex(0)
|
||||
if frame:
|
||||
# Print some simple frame info
|
||||
print frame
|
||||
function = frame.GetFunction()
|
||||
# See if we have debug info (a function)
|
||||
if function:
|
||||
# We do have a function, print some info for the function
|
||||
# We do have a function, print some info for the
|
||||
# function
|
||||
print function
|
||||
# Now get all instructions for this function and print them
|
||||
# Now get all instructions for this function and print
|
||||
# them
|
||||
insts = function.GetInstructions(target)
|
||||
disassemble_instructions (insts)
|
||||
disassemble_instructions(insts)
|
||||
else:
|
||||
# See if we have a symbol in the symbol table for where we stopped
|
||||
symbol = frame.GetSymbol();
|
||||
# See if we have a symbol in the symbol table for where
|
||||
# we stopped
|
||||
symbol = frame.GetSymbol()
|
||||
if symbol:
|
||||
# We do have a symbol, print some info for the symbol
|
||||
# We do have a symbol, print some info for the
|
||||
# symbol
|
||||
print symbol
|
||||
# Now get all instructions for this symbol and print them
|
||||
# Now get all instructions for this symbol and
|
||||
# print them
|
||||
insts = symbol.GetInstructions(target)
|
||||
disassemble_instructions (insts)
|
||||
disassemble_instructions(insts)
|
||||
|
||||
registerList = frame.GetRegisters()
|
||||
print "Frame registers (size of register set = %d):" % registerList.GetSize()
|
||||
for value in registerList:
|
||||
#print value
|
||||
# print value
|
||||
print "%s (number of children = %d):" % (value.GetName(), value.GetNumChildren())
|
||||
for child in value:
|
||||
print "Name: ", child.GetName(), " Value: ", child.GetValue()
|
||||
@@ -111,9 +119,8 @@ if target:
|
||||
elif state == lldb.eStateExited:
|
||||
print "Didn't hit the breakpoint at main, program has exited..."
|
||||
else:
|
||||
print "Unexpected process state: %s, killing process..." % debugger.StateAsCString (state)
|
||||
print "Unexpected process state: %s, killing process..." % debugger.StateAsCString(state)
|
||||
process.Kill()
|
||||
|
||||
|
||||
|
||||
lldb.SBDebugger.Terminate()
|
||||
|
||||
@@ -4,16 +4,17 @@ import string
|
||||
import struct
|
||||
import sys
|
||||
|
||||
|
||||
class FileExtract:
|
||||
'''Decode binary data from a file'''
|
||||
|
||||
def __init__(self, f, b = '='):
|
||||
|
||||
def __init__(self, f, b='='):
|
||||
'''Initialize with an open binary file and optional byte order'''
|
||||
|
||||
|
||||
self.file = f
|
||||
self.byte_order = b
|
||||
self.offsets = list()
|
||||
|
||||
|
||||
def set_byte_order(self, b):
|
||||
'''Set the byte order, valid values are "big", "little", "swap", "native", "<", ">", "@", "="'''
|
||||
if b == 'big':
|
||||
@@ -32,18 +33,18 @@ class FileExtract:
|
||||
|
||||
def is_in_memory(self):
|
||||
return False
|
||||
|
||||
def seek(self, offset, whence = 0):
|
||||
|
||||
def seek(self, offset, whence=0):
|
||||
if self.file:
|
||||
return self.file.seek(offset, whence)
|
||||
raise ValueError
|
||||
raise ValueError
|
||||
|
||||
def tell(self):
|
||||
if self.file:
|
||||
return self.file.tell()
|
||||
raise ValueError
|
||||
|
||||
def read_size (self, byte_size):
|
||||
raise ValueError
|
||||
|
||||
def read_size(self, byte_size):
|
||||
s = self.file.read(byte_size)
|
||||
if len(s) != byte_size:
|
||||
return None
|
||||
@@ -53,12 +54,12 @@ class FileExtract:
|
||||
'''Push the current file offset and seek to "offset"'''
|
||||
self.offsets.append(self.file.tell())
|
||||
self.file.seek(offset, 0)
|
||||
|
||||
|
||||
def pop_offset_and_seek(self):
|
||||
'''Pop a previously pushed file offset, or do nothing if there were no previously pushed offsets'''
|
||||
if len(self.offsets) > 0:
|
||||
self.file.seek(self.offsets.pop())
|
||||
|
||||
|
||||
def get_sint8(self, fail_value=0):
|
||||
'''Extract a single int8_t from the binary file at the current file position, returns a single integer'''
|
||||
s = self.read_size(1)
|
||||
@@ -112,7 +113,7 @@ class FileExtract:
|
||||
return v
|
||||
else:
|
||||
return fail_value
|
||||
|
||||
|
||||
def get_sint64(self, fail_value=0):
|
||||
'''Extract a single int64_t from the binary file at the current file position, returns a single integer'''
|
||||
s = self.read_size(8)
|
||||
@@ -131,7 +132,11 @@ class FileExtract:
|
||||
else:
|
||||
return fail_value
|
||||
|
||||
def get_fixed_length_c_string(self, n, fail_value='', isprint_only_with_space_padding=False):
|
||||
def get_fixed_length_c_string(
|
||||
self,
|
||||
n,
|
||||
fail_value='',
|
||||
isprint_only_with_space_padding=False):
|
||||
'''Extract a single fixed length C string from the binary file at the current file position, returns a single C string'''
|
||||
s = self.read_size(n)
|
||||
if s:
|
||||
@@ -174,7 +179,7 @@ class FileExtract:
|
||||
|
||||
def get_n_sint16(self, n, fail_value=0):
|
||||
'''Extract "n" int16_t integers from the binary file at the current file position, returns a list of integers'''
|
||||
s = self.read_size(2*n)
|
||||
s = self.read_size(2 * n)
|
||||
if s:
|
||||
return struct.unpack(self.byte_order + ("%u" % n) + 'h', s)
|
||||
else:
|
||||
@@ -182,7 +187,7 @@ class FileExtract:
|
||||
|
||||
def get_n_uint16(self, n, fail_value=0):
|
||||
'''Extract "n" uint16_t integers from the binary file at the current file position, returns a list of integers'''
|
||||
s = self.read_size(2*n)
|
||||
s = self.read_size(2 * n)
|
||||
if s:
|
||||
return struct.unpack(self.byte_order + ("%u" % n) + 'H', s)
|
||||
else:
|
||||
@@ -190,7 +195,7 @@ class FileExtract:
|
||||
|
||||
def get_n_sint32(self, n, fail_value=0):
|
||||
'''Extract "n" int32_t integers from the binary file at the current file position, returns a list of integers'''
|
||||
s = self.read_size(4*n)
|
||||
s = self.read_size(4 * n)
|
||||
if s:
|
||||
return struct.unpack(self.byte_order + ("%u" % n) + 'i', s)
|
||||
else:
|
||||
@@ -198,7 +203,7 @@ class FileExtract:
|
||||
|
||||
def get_n_uint32(self, n, fail_value=0):
|
||||
'''Extract "n" uint32_t integers from the binary file at the current file position, returns a list of integers'''
|
||||
s = self.read_size(4*n)
|
||||
s = self.read_size(4 * n)
|
||||
if s:
|
||||
return struct.unpack(self.byte_order + ("%u" % n) + 'I', s)
|
||||
else:
|
||||
@@ -206,7 +211,7 @@ class FileExtract:
|
||||
|
||||
def get_n_sint64(self, n, fail_value=0):
|
||||
'''Extract "n" int64_t integers from the binary file at the current file position, returns a list of integers'''
|
||||
s = self.read_size(8*n)
|
||||
s = self.read_size(8 * n)
|
||||
if s:
|
||||
return struct.unpack(self.byte_order + ("%u" % n) + 'q', s)
|
||||
else:
|
||||
@@ -214,7 +219,7 @@ class FileExtract:
|
||||
|
||||
def get_n_uint64(self, n, fail_value=0):
|
||||
'''Extract "n" uint64_t integers from the binary file at the current file position, returns a list of integers'''
|
||||
s = self.read_size(8*n)
|
||||
s = self.read_size(8 * n)
|
||||
if s:
|
||||
return struct.unpack(self.byte_order + ("%u" % n) + 'Q', s)
|
||||
else:
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import lldb
|
||||
|
||||
|
||||
def disassemble(debugger, command, result, dict):
|
||||
if lldb.frame.function:
|
||||
instructions = lldb.frame.function.instructions
|
||||
@@ -9,7 +10,7 @@ def disassemble(debugger, command, result, dict):
|
||||
instructions = lldb.frame.symbol.instructions
|
||||
start_addr = lldb.frame.symbol.addr.load_addr
|
||||
name = lldb.frame.symbol.name
|
||||
|
||||
|
||||
for inst in instructions:
|
||||
inst_addr = inst.addr.load_addr
|
||||
inst_offset = inst_addr - start_addr
|
||||
@@ -18,7 +19,8 @@ def disassemble(debugger, command, result, dict):
|
||||
print "<%s + %-4u> 0x%x %8s %s ; %s" % (name, inst_offset, inst_addr, inst.mnemonic, inst.operands, comment)
|
||||
else:
|
||||
print "<%s + %-4u> 0x%x %8s %s" % (name, inst_offset, inst_addr, inst.mnemonic, inst.operands)
|
||||
|
||||
|
||||
# Install the command when the module gets imported
|
||||
lldb.debugger.HandleCommand('command script add -f gdb_disassemble.disassemble gdb-disassemble')
|
||||
print 'Installed "gdb-disassemble" command for disassembly'
|
||||
lldb.debugger.HandleCommand(
|
||||
'command script add -f gdb_disassemble.disassemble gdb-disassemble')
|
||||
print 'Installed "gdb-disassemble" command for disassembly'
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -15,58 +15,92 @@ import os
|
||||
import shlex
|
||||
import sys
|
||||
|
||||
|
||||
def get_globals(raw_path, options):
|
||||
error = lldb.SBError()
|
||||
# Resolve the path if needed
|
||||
path = os.path.expanduser(raw_path)
|
||||
# Create a target using path + options
|
||||
target = lldb.debugger.CreateTarget(path, options.arch, options.platform, False, error)
|
||||
target = lldb.debugger.CreateTarget(
|
||||
path, options.arch, options.platform, False, error)
|
||||
if target:
|
||||
# Get the executable module
|
||||
module = target.module[target.executable.basename]
|
||||
if module:
|
||||
# Keep track of which variables we have already looked up
|
||||
global_names = list()
|
||||
# Iterate through all symbols in the symbol table and watch for any DATA symbols
|
||||
# Iterate through all symbols in the symbol table and watch for any
|
||||
# DATA symbols
|
||||
for symbol in module.symbols:
|
||||
if symbol.type == lldb.eSymbolTypeData:
|
||||
# The symbol is a DATA symbol, lets try and find all global variables
|
||||
# The symbol is a DATA symbol, lets try and find all global variables
|
||||
# that match this name and print them
|
||||
global_name = symbol.name
|
||||
# Make sure we don't lookup the same variable twice
|
||||
if global_name not in global_names:
|
||||
global_names.append(global_name)
|
||||
# Find all global variables by name
|
||||
global_variable_list = module.FindGlobalVariables (target, global_name, lldb.UINT32_MAX)
|
||||
global_variable_list = module.FindGlobalVariables(
|
||||
target, global_name, lldb.UINT32_MAX)
|
||||
if global_variable_list:
|
||||
# Print results for anything that matched
|
||||
for global_variable in global_variable_list:
|
||||
print 'name = %s' % global_variable.name # returns the global variable name as a string
|
||||
print 'value = %s' % global_variable.value # Returns the variable value as a string
|
||||
# returns the global variable name as a string
|
||||
print 'name = %s' % global_variable.name
|
||||
# Returns the variable value as a string
|
||||
print 'value = %s' % global_variable.value
|
||||
print 'type = %s' % global_variable.type # Returns an lldb.SBType object
|
||||
print 'addr = %s' % global_variable.addr # Returns an lldb.SBAddress (section offset address) for this global
|
||||
print 'file_addr = 0x%x' % global_variable.addr.file_addr # Returns the file virtual address for this global
|
||||
print 'location = %s' % global_variable.location # returns the global variable value as a string
|
||||
print 'size = %s' % global_variable.size # Returns the size in bytes of this global variable
|
||||
# Returns an lldb.SBAddress (section offset
|
||||
# address) for this global
|
||||
print 'addr = %s' % global_variable.addr
|
||||
# Returns the file virtual address for this
|
||||
# global
|
||||
print 'file_addr = 0x%x' % global_variable.addr.file_addr
|
||||
# returns the global variable value as a string
|
||||
print 'location = %s' % global_variable.location
|
||||
# Returns the size in bytes of this global
|
||||
# variable
|
||||
print 'size = %s' % global_variable.size
|
||||
print
|
||||
|
||||
|
||||
def globals(command_args):
|
||||
'''Extract all globals from any arguments which must be paths to object files.'''
|
||||
usage = "usage: %prog [options] <PATH> [PATH ...]"
|
||||
description='''This command will find all globals in the specified object file and return an list() of lldb.SBValue objects (which might be empty).'''
|
||||
parser = optparse.OptionParser(description=description, prog='globals',usage=usage)
|
||||
parser.add_option('-v', '--verbose', action='store_true', dest='verbose', help='display verbose debug info', default=False)
|
||||
parser.add_option('-a', '--arch', type='string', metavar='arch', dest='arch', help='Specify an architecture (or triple) to use when extracting from a file.')
|
||||
parser.add_option('-p', '--platform', type='string', metavar='platform', dest='platform', help='Specify the platform to use when creating the debug target. Valid values include "localhost", "darwin-kernel", "ios-simulator", "remote-freebsd", "remote-macosx", "remote-ios", "remote-linux".')
|
||||
description = '''This command will find all globals in the specified object file and return an list() of lldb.SBValue objects (which might be empty).'''
|
||||
parser = optparse.OptionParser(
|
||||
description=description,
|
||||
prog='globals',
|
||||
usage=usage)
|
||||
parser.add_option(
|
||||
'-v',
|
||||
'--verbose',
|
||||
action='store_true',
|
||||
dest='verbose',
|
||||
help='display verbose debug info',
|
||||
default=False)
|
||||
parser.add_option(
|
||||
'-a',
|
||||
'--arch',
|
||||
type='string',
|
||||
metavar='arch',
|
||||
dest='arch',
|
||||
help='Specify an architecture (or triple) to use when extracting from a file.')
|
||||
parser.add_option(
|
||||
'-p',
|
||||
'--platform',
|
||||
type='string',
|
||||
metavar='platform',
|
||||
dest='platform',
|
||||
help='Specify the platform to use when creating the debug target. Valid values include "localhost", "darwin-kernel", "ios-simulator", "remote-freebsd", "remote-macosx", "remote-ios", "remote-linux".')
|
||||
try:
|
||||
(options, args) = parser.parse_args(command_args)
|
||||
except:
|
||||
return
|
||||
|
||||
|
||||
for path in args:
|
||||
get_globals (path, options)
|
||||
|
||||
get_globals(path, options)
|
||||
|
||||
if __name__ == '__main__':
|
||||
lldb.debugger = lldb.SBDebugger.Create()
|
||||
globals (sys.argv[1:])
|
||||
|
||||
globals(sys.argv[1:])
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import lldb, re
|
||||
import lldb
|
||||
import re
|
||||
|
||||
def parse_linespec (linespec, frame, result):
|
||||
|
||||
def parse_linespec(linespec, frame, result):
|
||||
"""Handles a subset of GDB-style linespecs. Specifically:
|
||||
|
||||
|
||||
number - A line in the current file
|
||||
+offset - The line /offset/ lines after this line
|
||||
-offset - The line /offset/ lines before this line
|
||||
@@ -21,65 +23,73 @@ def parse_linespec (linespec, frame, result):
|
||||
|
||||
if (not matched):
|
||||
mo = re.match("^([0-9]+)$", linespec)
|
||||
if (mo != None):
|
||||
if (mo is not None):
|
||||
matched = True
|
||||
#print "Matched <linenum>"
|
||||
# print "Matched <linenum>"
|
||||
line_number = int(mo.group(1))
|
||||
line_entry = frame.GetLineEntry()
|
||||
if not line_entry.IsValid():
|
||||
result.AppendMessage("Specified a line in the current file, but the current frame doesn't have line table information.")
|
||||
result.AppendMessage(
|
||||
"Specified a line in the current file, but the current frame doesn't have line table information.")
|
||||
return
|
||||
breakpoint = target.BreakpointCreateByLocation (line_entry.GetFileSpec(), line_number)
|
||||
breakpoint = target.BreakpointCreateByLocation(
|
||||
line_entry.GetFileSpec(), line_number)
|
||||
|
||||
if (not matched):
|
||||
mo = re.match("^\+([0-9]+)$", linespec)
|
||||
if (mo != None):
|
||||
if (mo is not None):
|
||||
matched = True
|
||||
#print "Matched +<count>"
|
||||
# print "Matched +<count>"
|
||||
line_number = int(mo.group(1))
|
||||
line_entry = frame.GetLineEntry()
|
||||
if not line_entry.IsValid():
|
||||
result.AppendMessage("Specified a line in the current file, but the current frame doesn't have line table information.")
|
||||
result.AppendMessage(
|
||||
"Specified a line in the current file, but the current frame doesn't have line table information.")
|
||||
return
|
||||
breakpoint = target.BreakpointCreateByLocation(line_entry.GetFileSpec(), (line_entry.GetLine() + line_number))
|
||||
|
||||
breakpoint = target.BreakpointCreateByLocation(
|
||||
line_entry.GetFileSpec(), (line_entry.GetLine() + line_number))
|
||||
|
||||
if (not matched):
|
||||
mo = re.match("^\-([0-9]+)$", linespec)
|
||||
if (mo != None):
|
||||
if (mo is not None):
|
||||
matched = True
|
||||
#print "Matched -<count>"
|
||||
# print "Matched -<count>"
|
||||
line_number = int(mo.group(1))
|
||||
line_entry = frame.GetLineEntry()
|
||||
if not line_entry.IsValid():
|
||||
result.AppendMessage("Specified a line in the current file, but the current frame doesn't have line table information.")
|
||||
result.AppendMessage(
|
||||
"Specified a line in the current file, but the current frame doesn't have line table information.")
|
||||
return
|
||||
breakpoint = target.BreakpointCreateByLocation(line_entry.GetFileSpec(), (line_entry.GetLine() - line_number))
|
||||
breakpoint = target.BreakpointCreateByLocation(
|
||||
line_entry.GetFileSpec(), (line_entry.GetLine() - line_number))
|
||||
|
||||
if (not matched):
|
||||
mo = re.match("^(.*):([0-9]+)$", linespec)
|
||||
if (mo != None):
|
||||
if (mo is not None):
|
||||
matched = True
|
||||
#print "Matched <filename>:<linenum>"
|
||||
# print "Matched <filename>:<linenum>"
|
||||
file_name = mo.group(1)
|
||||
line_number = int(mo.group(2))
|
||||
breakpoint = target.BreakpointCreateByLocation(file_name, line_number)
|
||||
breakpoint = target.BreakpointCreateByLocation(
|
||||
file_name, line_number)
|
||||
|
||||
if (not matched):
|
||||
mo = re.match("\*((0x)?([0-9a-f]+))$", linespec)
|
||||
if (mo != None):
|
||||
if (mo is not None):
|
||||
matched = True
|
||||
#print "Matched <address-expression>"
|
||||
# print "Matched <address-expression>"
|
||||
address = long(mo.group(1), base=0)
|
||||
breakpoint = target.BreakpointCreateByAddress(address)
|
||||
|
||||
if (not matched):
|
||||
#print "Trying <function-name>"
|
||||
# print "Trying <function-name>"
|
||||
breakpoint = target.BreakpointCreateByName(linespec)
|
||||
|
||||
num_locations = breakpoint.GetNumLocations()
|
||||
|
||||
if (num_locations == 0):
|
||||
result.AppendMessage("The line specification provided doesn't resolve to any addresses.")
|
||||
result.AppendMessage(
|
||||
"The line specification provided doesn't resolve to any addresses.")
|
||||
|
||||
addr_list = []
|
||||
|
||||
@@ -91,6 +101,7 @@ def parse_linespec (linespec, frame, result):
|
||||
|
||||
return addr_list
|
||||
|
||||
|
||||
def usage_string():
|
||||
return """ Sets the program counter to a specific address.
|
||||
|
||||
@@ -106,7 +117,8 @@ Command Options Usage:
|
||||
|
||||
<location-id> serves to disambiguate when multiple locations could be meant."""
|
||||
|
||||
def jump (debugger, command, result, internal_dict):
|
||||
|
||||
def jump(debugger, command, result, internal_dict):
|
||||
if (command == ""):
|
||||
result.AppendMessage(usage_string())
|
||||
|
||||
@@ -151,17 +163,28 @@ def jump (debugger, command, result, internal_dict):
|
||||
if (desired_index >= 0) and (desired_index < len(addresses)):
|
||||
desired_address = addresses[desired_index]
|
||||
else:
|
||||
result.AppendMessage("Desired index " + args[1] + " is not one of the options.")
|
||||
result.AppendMessage(
|
||||
"Desired index " +
|
||||
args[1] +
|
||||
" is not one of the options.")
|
||||
return
|
||||
else:
|
||||
index = 0
|
||||
result.AppendMessage("The specified location resolves to multiple targets.");
|
||||
result.AppendMessage(
|
||||
"The specified location resolves to multiple targets.")
|
||||
for address in addresses:
|
||||
stream.Clear()
|
||||
address.GetDescription(stream)
|
||||
result.AppendMessage(" Location ID " + str(index) + ": " + stream.GetData())
|
||||
result.AppendMessage(
|
||||
" Location ID " +
|
||||
str(index) +
|
||||
": " +
|
||||
stream.GetData())
|
||||
index = index + 1
|
||||
result.AppendMessage("Please type 'jump " + command + " <location-id>' to choose one.")
|
||||
result.AppendMessage(
|
||||
"Please type 'jump " +
|
||||
command +
|
||||
" <location-id>' to choose one.")
|
||||
return
|
||||
|
||||
frame.SetPC(desired_address.GetLoadAddress(target))
|
||||
|
||||
@@ -6,18 +6,29 @@ import shlex
|
||||
import string
|
||||
import sys
|
||||
|
||||
def create_dump_module_line_tables_options ():
|
||||
|
||||
def create_dump_module_line_tables_options():
|
||||
usage = "usage: dump_module_line_tables [options] MODULE1 [MODULE2 ...]"
|
||||
description='''Dumps all line tables from all compile units for any modules specified as arguments. Specifying the --verbose flag will output address ranges for each line entry.'''
|
||||
parser = optparse.OptionParser(description=description, prog='start_gdb_log',usage=usage)
|
||||
parser.add_option('-v', '--verbose', action='store_true', dest='verbose', help='Display verbose output.', default=False)
|
||||
description = '''Dumps all line tables from all compile units for any modules specified as arguments. Specifying the --verbose flag will output address ranges for each line entry.'''
|
||||
parser = optparse.OptionParser(
|
||||
description=description,
|
||||
prog='start_gdb_log',
|
||||
usage=usage)
|
||||
parser.add_option(
|
||||
'-v',
|
||||
'--verbose',
|
||||
action='store_true',
|
||||
dest='verbose',
|
||||
help='Display verbose output.',
|
||||
default=False)
|
||||
return parser
|
||||
|
||||
|
||||
|
||||
def dump_module_line_tables(debugger, command, result, dict):
|
||||
'''Dumps all line tables from all compile units for any modules specified as arguments.'''
|
||||
command_args = shlex.split(command)
|
||||
|
||||
parser = create_dump_module_line_tables_options ()
|
||||
|
||||
parser = create_dump_module_line_tables_options()
|
||||
try:
|
||||
(options, args) = parser.parse_args(command_args)
|
||||
except:
|
||||
@@ -27,33 +38,41 @@ def dump_module_line_tables(debugger, command, result, dict):
|
||||
lldb.target = target
|
||||
for module_name in command_args:
|
||||
result.PutCString('Searching for module "%s"' % (module_name,))
|
||||
module_fspec = lldb.SBFileSpec (module_name, False)
|
||||
module = target.FindModule (module_fspec);
|
||||
module_fspec = lldb.SBFileSpec(module_name, False)
|
||||
module = target.FindModule(module_fspec)
|
||||
if module:
|
||||
for cu_idx in range (module.GetNumCompileUnits()):
|
||||
for cu_idx in range(module.GetNumCompileUnits()):
|
||||
cu = module.GetCompileUnitAtIndex(cu_idx)
|
||||
result.PutCString("\n%s:" % (cu.file))
|
||||
for line_idx in range(cu.GetNumLineEntries()):
|
||||
line_entry = cu.GetLineEntryAtIndex(line_idx)
|
||||
start_file_addr = line_entry.addr.file_addr
|
||||
end_file_addr = line_entry.end_addr.file_addr
|
||||
# If the two addresses are equal, this line table entry is a termination entry
|
||||
# If the two addresses are equal, this line table entry
|
||||
# is a termination entry
|
||||
if options.verbose:
|
||||
if start_file_addr != end_file_addr:
|
||||
result.PutCString('[%#x - %#x): %s' % (start_file_addr, end_file_addr, line_entry))
|
||||
result.PutCString(
|
||||
'[%#x - %#x): %s' %
|
||||
(start_file_addr, end_file_addr, line_entry))
|
||||
else:
|
||||
if start_file_addr == end_file_addr:
|
||||
result.PutCString('%#x: END' % (start_file_addr))
|
||||
result.PutCString('%#x: END' %
|
||||
(start_file_addr))
|
||||
else:
|
||||
result.PutCString('%#x: %s' % (start_file_addr, line_entry))
|
||||
result.PutCString(
|
||||
'%#x: %s' %
|
||||
(start_file_addr, line_entry))
|
||||
if start_file_addr == end_file_addr:
|
||||
result.Printf("\n")
|
||||
else:
|
||||
result.PutCString ("no module for '%s'" % module)
|
||||
result.PutCString("no module for '%s'" % module)
|
||||
else:
|
||||
result.PutCString ("error: invalid target")
|
||||
result.PutCString("error: invalid target")
|
||||
|
||||
parser = create_dump_module_line_tables_options ()
|
||||
parser = create_dump_module_line_tables_options()
|
||||
dump_module_line_tables.__doc__ = parser.format_help()
|
||||
lldb.debugger.HandleCommand('command script add -f %s.dump_module_line_tables dump_module_line_tables' % __name__)
|
||||
print 'Installed "dump_module_line_tables" command'
|
||||
lldb.debugger.HandleCommand(
|
||||
'command script add -f %s.dump_module_line_tables dump_module_line_tables' %
|
||||
__name__)
|
||||
print 'Installed "dump_module_line_tables" command'
|
||||
|
||||
@@ -6,7 +6,9 @@ import sys
|
||||
from Tkinter import *
|
||||
import ttk
|
||||
|
||||
|
||||
class ValueTreeItemDelegate(object):
|
||||
|
||||
def __init__(self, value):
|
||||
self.value = value
|
||||
|
||||
@@ -24,36 +26,44 @@ class ValueTreeItemDelegate(object):
|
||||
if summary is None:
|
||||
summary = ''
|
||||
has_children = self.value.MightHaveChildren()
|
||||
return { '#0' : name,
|
||||
'typename' : typename,
|
||||
'value' : value,
|
||||
'summary' : summary,
|
||||
'children' : has_children,
|
||||
'tree-item-delegate' : self }
|
||||
|
||||
return {'#0': name,
|
||||
'typename': typename,
|
||||
'value': value,
|
||||
'summary': summary,
|
||||
'children': has_children,
|
||||
'tree-item-delegate': self}
|
||||
|
||||
def get_child_item_dictionaries(self):
|
||||
item_dicts = list()
|
||||
for i in range(self.value.num_children):
|
||||
item_delegate = ValueTreeItemDelegate(self.value.GetChildAtIndex(i))
|
||||
item_delegate = ValueTreeItemDelegate(
|
||||
self.value.GetChildAtIndex(i))
|
||||
item_dicts.append(item_delegate.get_item_dictionary())
|
||||
return item_dicts
|
||||
|
||||
|
||||
class FrameTreeItemDelegate(object):
|
||||
|
||||
def __init__(self, frame):
|
||||
self.frame = frame
|
||||
|
||||
def get_item_dictionary(self):
|
||||
id = self.frame.GetFrameID()
|
||||
name = 'frame #%u' % (id);
|
||||
name = 'frame #%u' % (id)
|
||||
value = '0x%16.16x' % (self.frame.GetPC())
|
||||
stream = lldb.SBStream()
|
||||
self.frame.GetDescription(stream)
|
||||
summary = stream.GetData().split("`")[1]
|
||||
return { '#0' : name,
|
||||
'value': value,
|
||||
'summary': summary,
|
||||
'children' : self.frame.GetVariables(True, True, True, True).GetSize() > 0,
|
||||
'tree-item-delegate' : self }
|
||||
return {
|
||||
'#0': name,
|
||||
'value': value,
|
||||
'summary': summary,
|
||||
'children': self.frame.GetVariables(
|
||||
True,
|
||||
True,
|
||||
True,
|
||||
True).GetSize() > 0,
|
||||
'tree-item-delegate': self}
|
||||
|
||||
def get_child_item_dictionaries(self):
|
||||
item_dicts = list()
|
||||
@@ -64,29 +74,33 @@ class FrameTreeItemDelegate(object):
|
||||
item_dicts.append(item_delegate.get_item_dictionary())
|
||||
return item_dicts
|
||||
|
||||
|
||||
class ThreadTreeItemDelegate(object):
|
||||
def __init__(self, thread):
|
||||
self.thread = thread
|
||||
|
||||
def get_item_dictionary(self):
|
||||
num_frames = self.thread.GetNumFrames()
|
||||
name = 'thread #%u' % (self.thread.GetIndexID())
|
||||
value = '0x%x' % (self.thread.GetThreadID())
|
||||
summary = '%u frames' % (num_frames)
|
||||
return { '#0' : name,
|
||||
'value': value,
|
||||
def __init__(self, thread):
|
||||
self.thread = thread
|
||||
|
||||
def get_item_dictionary(self):
|
||||
num_frames = self.thread.GetNumFrames()
|
||||
name = 'thread #%u' % (self.thread.GetIndexID())
|
||||
value = '0x%x' % (self.thread.GetThreadID())
|
||||
summary = '%u frames' % (num_frames)
|
||||
return {'#0': name,
|
||||
'value': value,
|
||||
'summary': summary,
|
||||
'children' : num_frames > 0,
|
||||
'tree-item-delegate' : self }
|
||||
'children': num_frames > 0,
|
||||
'tree-item-delegate': self}
|
||||
|
||||
def get_child_item_dictionaries(self):
|
||||
item_dicts = list()
|
||||
for frame in self.thread:
|
||||
item_delegate = FrameTreeItemDelegate(frame)
|
||||
item_dicts.append(item_delegate.get_item_dictionary())
|
||||
return item_dicts
|
||||
|
||||
|
||||
def get_child_item_dictionaries(self):
|
||||
item_dicts = list()
|
||||
for frame in self.thread:
|
||||
item_delegate = FrameTreeItemDelegate(frame)
|
||||
item_dicts.append(item_delegate.get_item_dictionary())
|
||||
return item_dicts
|
||||
|
||||
class ProcessTreeItemDelegate(object):
|
||||
|
||||
def __init__(self, process):
|
||||
self.process = process
|
||||
|
||||
@@ -95,11 +109,11 @@ class ProcessTreeItemDelegate(object):
|
||||
num_threads = self.process.GetNumThreads()
|
||||
value = str(self.process.GetProcessID())
|
||||
summary = self.process.target.executable.fullpath
|
||||
return { '#0' : 'process',
|
||||
'value': value,
|
||||
'summary': summary,
|
||||
'children' : num_threads > 0,
|
||||
'tree-item-delegate' : self }
|
||||
return {'#0': 'process',
|
||||
'value': value,
|
||||
'summary': summary,
|
||||
'children': num_threads > 0,
|
||||
'tree-item-delegate': self}
|
||||
|
||||
def get_child_item_dictionaries(self):
|
||||
item_dicts = list()
|
||||
@@ -108,18 +122,20 @@ class ProcessTreeItemDelegate(object):
|
||||
item_dicts.append(item_delegate.get_item_dictionary())
|
||||
return item_dicts
|
||||
|
||||
|
||||
class TargetTreeItemDelegate(object):
|
||||
|
||||
def __init__(self, target):
|
||||
self.target = target
|
||||
|
||||
def get_item_dictionary(self):
|
||||
value = str(self.target.triple)
|
||||
summary = self.target.executable.fullpath
|
||||
return { '#0' : 'target',
|
||||
'value': value,
|
||||
'summary': summary,
|
||||
'children' : True,
|
||||
'tree-item-delegate' : self }
|
||||
return {'#0': 'target',
|
||||
'value': value,
|
||||
'summary': summary,
|
||||
'children': True,
|
||||
'tree-item-delegate': self}
|
||||
|
||||
def get_child_item_dictionaries(self):
|
||||
item_dicts = list()
|
||||
@@ -127,7 +143,9 @@ class TargetTreeItemDelegate(object):
|
||||
item_dicts.append(image_item_delegate.get_item_dictionary())
|
||||
return item_dicts
|
||||
|
||||
|
||||
class TargetImagesTreeItemDelegate(object):
|
||||
|
||||
def __init__(self, target):
|
||||
self.target = target
|
||||
|
||||
@@ -135,21 +153,24 @@ class TargetImagesTreeItemDelegate(object):
|
||||
value = str(self.target.triple)
|
||||
summary = self.target.executable.fullpath
|
||||
num_modules = self.target.GetNumModules()
|
||||
return { '#0' : 'images',
|
||||
'value': '',
|
||||
'summary': '%u images' % num_modules,
|
||||
'children' : num_modules > 0,
|
||||
'tree-item-delegate' : self }
|
||||
return {'#0': 'images',
|
||||
'value': '',
|
||||
'summary': '%u images' % num_modules,
|
||||
'children': num_modules > 0,
|
||||
'tree-item-delegate': self}
|
||||
|
||||
def get_child_item_dictionaries(self):
|
||||
item_dicts = list()
|
||||
for i in range(self.target.GetNumModules()):
|
||||
module = self.target.GetModuleAtIndex(i)
|
||||
image_item_delegate = ModuleTreeItemDelegate(self.target, module, i)
|
||||
image_item_delegate = ModuleTreeItemDelegate(
|
||||
self.target, module, i)
|
||||
item_dicts.append(image_item_delegate.get_item_dictionary())
|
||||
return item_dicts
|
||||
|
||||
|
||||
class ModuleTreeItemDelegate(object):
|
||||
|
||||
def __init__(self, target, module, index):
|
||||
self.target = target
|
||||
self.module = module
|
||||
@@ -159,25 +180,30 @@ class ModuleTreeItemDelegate(object):
|
||||
name = 'module %u' % (self.index)
|
||||
value = self.module.file.basename
|
||||
summary = self.module.file.dirname
|
||||
return { '#0' : name,
|
||||
'value': value,
|
||||
'summary': summary,
|
||||
'children' : True,
|
||||
'tree-item-delegate' : self }
|
||||
return {'#0': name,
|
||||
'value': value,
|
||||
'summary': summary,
|
||||
'children': True,
|
||||
'tree-item-delegate': self}
|
||||
|
||||
def get_child_item_dictionaries(self):
|
||||
item_dicts = list()
|
||||
sections_item_delegate = ModuleSectionsTreeItemDelegate(self.target, self.module)
|
||||
sections_item_delegate = ModuleSectionsTreeItemDelegate(
|
||||
self.target, self.module)
|
||||
item_dicts.append(sections_item_delegate.get_item_dictionary())
|
||||
|
||||
symbols_item_delegate = ModuleSymbolsTreeItemDelegate(self.target, self.module)
|
||||
symbols_item_delegate = ModuleSymbolsTreeItemDelegate(
|
||||
self.target, self.module)
|
||||
item_dicts.append(symbols_item_delegate.get_item_dictionary())
|
||||
|
||||
comp_units_item_delegate = ModuleCompileUnitsTreeItemDelegate(self.target, self.module)
|
||||
comp_units_item_delegate = ModuleCompileUnitsTreeItemDelegate(
|
||||
self.target, self.module)
|
||||
item_dicts.append(comp_units_item_delegate.get_item_dictionary())
|
||||
return item_dicts
|
||||
|
||||
|
||||
class ModuleSectionsTreeItemDelegate(object):
|
||||
|
||||
def __init__(self, target, module):
|
||||
self.target = target
|
||||
self.module = module
|
||||
@@ -186,11 +212,11 @@ class ModuleSectionsTreeItemDelegate(object):
|
||||
name = 'sections'
|
||||
value = ''
|
||||
summary = '%u sections' % (self.module.GetNumSections())
|
||||
return { '#0' : name,
|
||||
'value': value,
|
||||
'summary': summary,
|
||||
'children' : True,
|
||||
'tree-item-delegate' : self }
|
||||
return {'#0': name,
|
||||
'value': value,
|
||||
'summary': summary,
|
||||
'children': True,
|
||||
'tree-item-delegate': self}
|
||||
|
||||
def get_child_item_dictionaries(self):
|
||||
item_dicts = list()
|
||||
@@ -201,7 +227,9 @@ class ModuleSectionsTreeItemDelegate(object):
|
||||
item_dicts.append(image_item_delegate.get_item_dictionary())
|
||||
return item_dicts
|
||||
|
||||
|
||||
class SectionTreeItemDelegate(object):
|
||||
|
||||
def __init__(self, target, section):
|
||||
self.target = target
|
||||
self.section = section
|
||||
@@ -214,11 +242,11 @@ class SectionTreeItemDelegate(object):
|
||||
else:
|
||||
value = '0x%16.16x *' % (self.section.file_addr)
|
||||
summary = ''
|
||||
return { '#0' : name,
|
||||
'value': value,
|
||||
'summary': summary,
|
||||
'children' : self.section.GetNumSubSections() > 0,
|
||||
'tree-item-delegate' : self }
|
||||
return {'#0': name,
|
||||
'value': value,
|
||||
'summary': summary,
|
||||
'children': self.section.GetNumSubSections() > 0,
|
||||
'tree-item-delegate': self}
|
||||
|
||||
def get_child_item_dictionaries(self):
|
||||
item_dicts = list()
|
||||
@@ -226,10 +254,12 @@ class SectionTreeItemDelegate(object):
|
||||
for i in range(num_sections):
|
||||
section = self.section.GetSubSectionAtIndex(i)
|
||||
image_item_delegate = SectionTreeItemDelegate(self.target, section)
|
||||
item_dicts.append(image_item_delegate.get_item_dictionary())
|
||||
item_dicts.append(image_item_delegate.get_item_dictionary())
|
||||
return item_dicts
|
||||
|
||||
|
||||
class ModuleCompileUnitsTreeItemDelegate(object):
|
||||
|
||||
def __init__(self, target, module):
|
||||
self.target = target
|
||||
self.module = module
|
||||
@@ -238,11 +268,11 @@ class ModuleCompileUnitsTreeItemDelegate(object):
|
||||
name = 'compile units'
|
||||
value = ''
|
||||
summary = '%u compile units' % (self.module.GetNumSections())
|
||||
return { '#0' : name,
|
||||
'value': value,
|
||||
'summary': summary,
|
||||
'children' : self.module.GetNumCompileUnits() > 0,
|
||||
'tree-item-delegate' : self }
|
||||
return {'#0': name,
|
||||
'value': value,
|
||||
'summary': summary,
|
||||
'children': self.module.GetNumCompileUnits() > 0,
|
||||
'tree-item-delegate': self}
|
||||
|
||||
def get_child_item_dictionaries(self):
|
||||
item_dicts = list()
|
||||
@@ -253,7 +283,9 @@ class ModuleCompileUnitsTreeItemDelegate(object):
|
||||
item_dicts.append(image_item_delegate.get_item_dictionary())
|
||||
return item_dicts
|
||||
|
||||
|
||||
class CompileUnitTreeItemDelegate(object):
|
||||
|
||||
def __init__(self, target, cu):
|
||||
self.target = target
|
||||
self.cu = cu
|
||||
@@ -263,11 +295,11 @@ class CompileUnitTreeItemDelegate(object):
|
||||
value = ''
|
||||
num_lines = self.cu.GetNumLineEntries()
|
||||
summary = ''
|
||||
return { '#0' : name,
|
||||
'value': value,
|
||||
'summary': summary,
|
||||
'children' : num_lines > 0,
|
||||
'tree-item-delegate' : self }
|
||||
return {'#0': name,
|
||||
'value': value,
|
||||
'summary': summary,
|
||||
'children': num_lines > 0,
|
||||
'tree-item-delegate': self}
|
||||
|
||||
def get_child_item_dictionaries(self):
|
||||
item_dicts = list()
|
||||
@@ -275,7 +307,9 @@ class CompileUnitTreeItemDelegate(object):
|
||||
item_dicts.append(item_delegate.get_item_dictionary())
|
||||
return item_dicts
|
||||
|
||||
|
||||
class LineTableTreeItemDelegate(object):
|
||||
|
||||
def __init__(self, target, cu):
|
||||
self.target = target
|
||||
self.cu = cu
|
||||
@@ -285,22 +319,25 @@ class LineTableTreeItemDelegate(object):
|
||||
value = ''
|
||||
num_lines = self.cu.GetNumLineEntries()
|
||||
summary = '%u line entries' % (num_lines)
|
||||
return { '#0' : name,
|
||||
'value': value,
|
||||
'summary': summary,
|
||||
'children' : num_lines > 0,
|
||||
'tree-item-delegate' : self }
|
||||
return {'#0': name,
|
||||
'value': value,
|
||||
'summary': summary,
|
||||
'children': num_lines > 0,
|
||||
'tree-item-delegate': self}
|
||||
|
||||
def get_child_item_dictionaries(self):
|
||||
item_dicts = list()
|
||||
num_lines = self.cu.GetNumLineEntries()
|
||||
for i in range(num_lines):
|
||||
line_entry = self.cu.GetLineEntryAtIndex(i)
|
||||
item_delegate = LineEntryTreeItemDelegate(self.target, line_entry, i)
|
||||
item_delegate = LineEntryTreeItemDelegate(
|
||||
self.target, line_entry, i)
|
||||
item_dicts.append(item_delegate.get_item_dictionary())
|
||||
return item_dicts
|
||||
|
||||
|
||||
class LineEntryTreeItemDelegate(object):
|
||||
|
||||
def __init__(self, target, line_entry, index):
|
||||
self.target = target
|
||||
self.line_entry = line_entry
|
||||
@@ -314,18 +351,21 @@ class LineEntryTreeItemDelegate(object):
|
||||
value = '0x%16.16x' % (load_addr)
|
||||
else:
|
||||
value = '0x%16.16x *' % (address.file_addr)
|
||||
summary = self.line_entry.GetFileSpec().fullpath + ':' + str(self.line_entry.line)
|
||||
return { '#0' : name,
|
||||
'value': value,
|
||||
'summary': summary,
|
||||
'children' : False,
|
||||
'tree-item-delegate' : self }
|
||||
summary = self.line_entry.GetFileSpec().fullpath + ':' + \
|
||||
str(self.line_entry.line)
|
||||
return {'#0': name,
|
||||
'value': value,
|
||||
'summary': summary,
|
||||
'children': False,
|
||||
'tree-item-delegate': self}
|
||||
|
||||
def get_child_item_dictionaries(self):
|
||||
item_dicts = list()
|
||||
return item_dicts
|
||||
|
||||
|
||||
class InstructionTreeItemDelegate(object):
|
||||
|
||||
def __init__(self, target, instr):
|
||||
self.target = target
|
||||
self.instr = instr
|
||||
@@ -337,15 +377,18 @@ class InstructionTreeItemDelegate(object):
|
||||
name = '0x%16.16x' % (load_addr)
|
||||
else:
|
||||
name = '0x%16.16x *' % (address.file_addr)
|
||||
value = self.instr.GetMnemonic(self.target) + ' ' + self.instr.GetOperands(self.target)
|
||||
value = self.instr.GetMnemonic(
|
||||
self.target) + ' ' + self.instr.GetOperands(self.target)
|
||||
summary = self.instr.GetComment(self.target)
|
||||
return { '#0' : name,
|
||||
'value': value,
|
||||
'summary': summary,
|
||||
'children' : False,
|
||||
'tree-item-delegate' : self }
|
||||
return {'#0': name,
|
||||
'value': value,
|
||||
'summary': summary,
|
||||
'children': False,
|
||||
'tree-item-delegate': self}
|
||||
|
||||
|
||||
class ModuleSymbolsTreeItemDelegate(object):
|
||||
|
||||
def __init__(self, target, module):
|
||||
self.target = target
|
||||
self.module = module
|
||||
@@ -354,22 +397,25 @@ class ModuleSymbolsTreeItemDelegate(object):
|
||||
name = 'symbols'
|
||||
value = ''
|
||||
summary = '%u symbols' % (self.module.GetNumSymbols())
|
||||
return { '#0' : name,
|
||||
'value': value,
|
||||
'summary': summary,
|
||||
'children' : True,
|
||||
'tree-item-delegate' : self }
|
||||
return {'#0': name,
|
||||
'value': value,
|
||||
'summary': summary,
|
||||
'children': True,
|
||||
'tree-item-delegate': self}
|
||||
|
||||
def get_child_item_dictionaries(self):
|
||||
item_dicts = list()
|
||||
num_symbols = self.module.GetNumSymbols()
|
||||
for i in range(num_symbols):
|
||||
symbol = self.module.GetSymbolAtIndex(i)
|
||||
image_item_delegate = SymbolTreeItemDelegate(self.target, symbol, i)
|
||||
image_item_delegate = SymbolTreeItemDelegate(
|
||||
self.target, symbol, i)
|
||||
item_dicts.append(image_item_delegate.get_item_dictionary())
|
||||
return item_dicts
|
||||
|
||||
|
||||
class SymbolTreeItemDelegate(object):
|
||||
|
||||
def __init__(self, target, symbol, index):
|
||||
self.target = target
|
||||
self.symbol = symbol
|
||||
@@ -384,20 +430,19 @@ class SymbolTreeItemDelegate(object):
|
||||
else:
|
||||
value = '0x%16.16x *' % (address.file_addr)
|
||||
summary = self.symbol.name
|
||||
return { '#0' : name,
|
||||
'value': value,
|
||||
'summary': summary,
|
||||
'children' : False,
|
||||
'tree-item-delegate' : self }
|
||||
return {'#0': name,
|
||||
'value': value,
|
||||
'summary': summary,
|
||||
'children': False,
|
||||
'tree-item-delegate': self}
|
||||
|
||||
def get_child_item_dictionaries(self):
|
||||
item_dicts = list()
|
||||
return item_dicts
|
||||
|
||||
|
||||
|
||||
class DelegateTree(ttk.Frame):
|
||||
|
||||
|
||||
def __init__(self, column_dicts, delegate, title, name):
|
||||
ttk.Frame.__init__(self, name=name)
|
||||
self.pack(expand=Y, fill=BOTH)
|
||||
@@ -409,36 +454,42 @@ class DelegateTree(ttk.Frame):
|
||||
frame.pack(side=TOP, fill=BOTH, expand=Y)
|
||||
self._create_treeview(frame)
|
||||
self._populate_root()
|
||||
|
||||
|
||||
def _create_treeview(self, parent):
|
||||
frame = ttk.Frame(parent)
|
||||
frame.pack(side=TOP, fill=BOTH, expand=Y)
|
||||
|
||||
|
||||
column_ids = list()
|
||||
for i in range(1,len(self.columns_dicts)):
|
||||
for i in range(1, len(self.columns_dicts)):
|
||||
column_ids.append(self.columns_dicts[i]['id'])
|
||||
# create the tree and scrollbars
|
||||
self.tree = ttk.Treeview(columns=column_ids)
|
||||
|
||||
scroll_bar_v = ttk.Scrollbar(orient=VERTICAL, command= self.tree.yview)
|
||||
scroll_bar_h = ttk.Scrollbar(orient=HORIZONTAL, command= self.tree.xview)
|
||||
|
||||
scroll_bar_v = ttk.Scrollbar(orient=VERTICAL, command=self.tree.yview)
|
||||
scroll_bar_h = ttk.Scrollbar(
|
||||
orient=HORIZONTAL, command=self.tree.xview)
|
||||
self.tree['yscroll'] = scroll_bar_v.set
|
||||
self.tree['xscroll'] = scroll_bar_h.set
|
||||
|
||||
|
||||
# setup column headings and columns properties
|
||||
for columns_dict in self.columns_dicts:
|
||||
self.tree.heading(columns_dict['id'], text=columns_dict['text'], anchor=columns_dict['anchor'])
|
||||
self.tree.column(columns_dict['id'], stretch=columns_dict['stretch'])
|
||||
|
||||
self.tree.heading(
|
||||
columns_dict['id'],
|
||||
text=columns_dict['text'],
|
||||
anchor=columns_dict['anchor'])
|
||||
self.tree.column(
|
||||
columns_dict['id'],
|
||||
stretch=columns_dict['stretch'])
|
||||
|
||||
# add tree and scrollbars to frame
|
||||
self.tree.grid(in_=frame, row=0, column=0, sticky=NSEW)
|
||||
scroll_bar_v.grid(in_=frame, row=0, column=1, sticky=NS)
|
||||
scroll_bar_h.grid(in_=frame, row=1, column=0, sticky=EW)
|
||||
|
||||
|
||||
# set frame resizing priorities
|
||||
frame.rowconfigure(0, weight=1)
|
||||
frame.columnconfigure(0, weight=1)
|
||||
|
||||
|
||||
# action to perform when a node is expanded
|
||||
self.tree.bind('<<TreeviewOpen>>', self._update_tree)
|
||||
|
||||
@@ -453,22 +504,22 @@ class DelegateTree(ttk.Frame):
|
||||
first = False
|
||||
else:
|
||||
values.append(item_dict[columns_dict['id']])
|
||||
item_id = self.tree.insert (parent_id, # root item has an empty name
|
||||
END,
|
||||
text=name,
|
||||
values=values)
|
||||
item_id = self.tree.insert(parent_id, # root item has an empty name
|
||||
END,
|
||||
text=name,
|
||||
values=values)
|
||||
self.item_id_to_item_dict[item_id] = item_dict
|
||||
if item_dict['children']:
|
||||
self.tree.insert(item_id, END, text='dummy')
|
||||
|
||||
|
||||
def _populate_root(self):
|
||||
# use current directory as root node
|
||||
self.insert_items('', self.delegate.get_child_item_dictionaries())
|
||||
|
||||
|
||||
def _update_tree(self, event):
|
||||
# user expanded a node - build the related directory
|
||||
item_id = self.tree.focus() # the id of the expanded node
|
||||
children = self.tree.get_children (item_id)
|
||||
item_id = self.tree.focus() # the id of the expanded node
|
||||
children = self.tree.get_children(item_id)
|
||||
if len(children):
|
||||
first_child = children[0]
|
||||
# if the node only has a 'dummy' child, remove it and
|
||||
@@ -477,12 +528,15 @@ class DelegateTree(ttk.Frame):
|
||||
if self.tree.item(first_child, option='text') == 'dummy':
|
||||
self.tree.delete(first_child)
|
||||
item_dict = self.item_id_to_item_dict[item_id]
|
||||
item_dicts = item_dict['tree-item-delegate'].get_child_item_dictionaries()
|
||||
item_dicts = item_dict[
|
||||
'tree-item-delegate'].get_child_item_dictionaries()
|
||||
self.insert_items(item_id, item_dicts)
|
||||
|
||||
|
||||
@lldb.command("tk-variables")
|
||||
def tk_variable_display(debugger, command, result, dict):
|
||||
sys.argv = ['tk-variables'] # needed for tree creation in TK library as it uses sys.argv...
|
||||
# needed for tree creation in TK library as it uses sys.argv...
|
||||
sys.argv = ['tk-variables']
|
||||
target = debugger.GetSelectedTarget()
|
||||
if not target:
|
||||
print >>result, "invalid target"
|
||||
@@ -501,16 +555,22 @@ def tk_variable_display(debugger, command, result, dict):
|
||||
return
|
||||
# Parse command line args
|
||||
command_args = shlex.split(command)
|
||||
column_dicts = [{ 'id' : '#0' , 'text' : 'Name' , 'anchor' : W , 'stretch' : 0 },
|
||||
{ 'id' : 'typename', 'text' : 'Type' , 'anchor' : W , 'stretch' : 0 },
|
||||
{ 'id' : 'value' , 'text' : 'Value' , 'anchor' : W , 'stretch' : 0 },
|
||||
{ 'id' : 'summary' , 'text' : 'Summary', 'anchor' : W , 'stretch' : 1 }]
|
||||
tree = DelegateTree(column_dicts, FrameTreeItemDelegate(frame), 'Variables', 'lldb-tk-variables')
|
||||
column_dicts = [{'id': '#0', 'text': 'Name', 'anchor': W, 'stretch': 0},
|
||||
{'id': 'typename', 'text': 'Type', 'anchor': W, 'stretch': 0},
|
||||
{'id': 'value', 'text': 'Value', 'anchor': W, 'stretch': 0},
|
||||
{'id': 'summary', 'text': 'Summary', 'anchor': W, 'stretch': 1}]
|
||||
tree = DelegateTree(
|
||||
column_dicts,
|
||||
FrameTreeItemDelegate(frame),
|
||||
'Variables',
|
||||
'lldb-tk-variables')
|
||||
tree.mainloop()
|
||||
|
||||
|
||||
@lldb.command("tk-process")
|
||||
def tk_process_display(debugger, command, result, dict):
|
||||
sys.argv = ['tk-process'] # needed for tree creation in TK library as it uses sys.argv...
|
||||
# needed for tree creation in TK library as it uses sys.argv...
|
||||
sys.argv = ['tk-process']
|
||||
target = debugger.GetSelectedTarget()
|
||||
if not target:
|
||||
print >>result, "invalid target"
|
||||
@@ -520,25 +580,34 @@ def tk_process_display(debugger, command, result, dict):
|
||||
print >>result, "invalid process"
|
||||
return
|
||||
# Parse command line args
|
||||
columnd_dicts = [{ 'id' : '#0' , 'text' : 'Name' , 'anchor' : W , 'stretch' : 0 },
|
||||
{ 'id' : 'value' , 'text' : 'Value' , 'anchor' : W , 'stretch' : 0 },
|
||||
{ 'id' : 'summary', 'text' : 'Summary', 'anchor' : W , 'stretch' : 1 }];
|
||||
columnd_dicts = [{'id': '#0', 'text': 'Name', 'anchor': W, 'stretch': 0},
|
||||
{'id': 'value', 'text': 'Value', 'anchor': W, 'stretch': 0},
|
||||
{'id': 'summary', 'text': 'Summary', 'anchor': W, 'stretch': 1}]
|
||||
command_args = shlex.split(command)
|
||||
tree = DelegateTree(columnd_dicts, ProcessTreeItemDelegate(process), 'Process', 'lldb-tk-process')
|
||||
tree = DelegateTree(
|
||||
columnd_dicts,
|
||||
ProcessTreeItemDelegate(process),
|
||||
'Process',
|
||||
'lldb-tk-process')
|
||||
tree.mainloop()
|
||||
|
||||
|
||||
@lldb.command("tk-target")
|
||||
def tk_target_display(debugger, command, result, dict):
|
||||
sys.argv = ['tk-target'] # needed for tree creation in TK library as it uses sys.argv...
|
||||
# needed for tree creation in TK library as it uses sys.argv...
|
||||
sys.argv = ['tk-target']
|
||||
target = debugger.GetSelectedTarget()
|
||||
if not target:
|
||||
print >>result, "invalid target"
|
||||
return
|
||||
# Parse command line args
|
||||
columnd_dicts = [{ 'id' : '#0' , 'text' : 'Name' , 'anchor' : W , 'stretch' : 0 },
|
||||
{ 'id' : 'value' , 'text' : 'Value' , 'anchor' : W , 'stretch' : 0 },
|
||||
{ 'id' : 'summary', 'text' : 'Summary', 'anchor' : W , 'stretch' : 1 }];
|
||||
columnd_dicts = [{'id': '#0', 'text': 'Name', 'anchor': W, 'stretch': 0},
|
||||
{'id': 'value', 'text': 'Value', 'anchor': W, 'stretch': 0},
|
||||
{'id': 'summary', 'text': 'Summary', 'anchor': W, 'stretch': 1}]
|
||||
command_args = shlex.split(command)
|
||||
tree = DelegateTree(columnd_dicts, TargetTreeItemDelegate(target), 'Target', 'lldb-tk-target')
|
||||
tree = DelegateTree(
|
||||
columnd_dicts,
|
||||
TargetTreeItemDelegate(target),
|
||||
'Target',
|
||||
'lldb-tk-target')
|
||||
tree.mainloop()
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4,7 +4,7 @@
|
||||
# Be sure to add the python path that points to the LLDB shared library.
|
||||
#
|
||||
# # To use this in the embedded python interpreter using "lldb" just
|
||||
# import it with the full path using the "command script import"
|
||||
# import it with the full path using the "command script import"
|
||||
# command
|
||||
# (lldb) command script import /path/to/cmdtemplate.py
|
||||
#----------------------------------------------------------------------
|
||||
@@ -15,7 +15,7 @@ import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
try:
|
||||
try:
|
||||
# Just try for LLDB in case PYTHONPATH is already correctly setup
|
||||
import lldb
|
||||
except ImportError:
|
||||
@@ -26,15 +26,20 @@ except ImportError:
|
||||
# On Darwin, try the currently selected Xcode directory
|
||||
xcode_dir = commands.getoutput("xcode-select --print-path")
|
||||
if xcode_dir:
|
||||
lldb_python_dirs.append(os.path.realpath(xcode_dir + '/../SharedFrameworks/LLDB.framework/Resources/Python'))
|
||||
lldb_python_dirs.append(xcode_dir + '/Library/PrivateFrameworks/LLDB.framework/Resources/Python')
|
||||
lldb_python_dirs.append('/System/Library/PrivateFrameworks/LLDB.framework/Resources/Python')
|
||||
lldb_python_dirs.append(
|
||||
os.path.realpath(
|
||||
xcode_dir +
|
||||
'/../SharedFrameworks/LLDB.framework/Resources/Python'))
|
||||
lldb_python_dirs.append(
|
||||
xcode_dir + '/Library/PrivateFrameworks/LLDB.framework/Resources/Python')
|
||||
lldb_python_dirs.append(
|
||||
'/System/Library/PrivateFrameworks/LLDB.framework/Resources/Python')
|
||||
success = False
|
||||
for lldb_python_dir in lldb_python_dirs:
|
||||
if os.path.exists(lldb_python_dir):
|
||||
if not (sys.path.__contains__(lldb_python_dir)):
|
||||
sys.path.append(lldb_python_dir)
|
||||
try:
|
||||
try:
|
||||
import lldb
|
||||
except ImportError:
|
||||
pass
|
||||
@@ -53,52 +58,129 @@ import string
|
||||
import struct
|
||||
import time
|
||||
|
||||
|
||||
def append_data_callback(option, opt_str, value, parser):
|
||||
if opt_str == "--uint8":
|
||||
int8 = int(value, 0)
|
||||
parser.values.data += struct.pack('1B',int8)
|
||||
parser.values.data += struct.pack('1B', int8)
|
||||
if opt_str == "--uint16":
|
||||
int16 = int(value, 0)
|
||||
parser.values.data += struct.pack('1H',int16)
|
||||
parser.values.data += struct.pack('1H', int16)
|
||||
if opt_str == "--uint32":
|
||||
int32 = int(value, 0)
|
||||
parser.values.data += struct.pack('1I',int32)
|
||||
parser.values.data += struct.pack('1I', int32)
|
||||
if opt_str == "--uint64":
|
||||
int64 = int(value, 0)
|
||||
parser.values.data += struct.pack('1Q',int64)
|
||||
parser.values.data += struct.pack('1Q', int64)
|
||||
if opt_str == "--int8":
|
||||
int8 = int(value, 0)
|
||||
parser.values.data += struct.pack('1b',int8)
|
||||
parser.values.data += struct.pack('1b', int8)
|
||||
if opt_str == "--int16":
|
||||
int16 = int(value, 0)
|
||||
parser.values.data += struct.pack('1h',int16)
|
||||
parser.values.data += struct.pack('1h', int16)
|
||||
if opt_str == "--int32":
|
||||
int32 = int(value, 0)
|
||||
parser.values.data += struct.pack('1i',int32)
|
||||
parser.values.data += struct.pack('1i', int32)
|
||||
if opt_str == "--int64":
|
||||
int64 = int(value, 0)
|
||||
parser.values.data += struct.pack('1q',int64)
|
||||
parser.values.data += struct.pack('1q', int64)
|
||||
|
||||
|
||||
def create_memfind_options():
|
||||
usage = "usage: %prog [options] STARTADDR [ENDADDR]"
|
||||
description='''This command can find data in a specified address range.
|
||||
description = '''This command can find data in a specified address range.
|
||||
Options are used to specify the data that is to be looked for and the options
|
||||
can be specified multiple times to look for longer streams of data.
|
||||
'''
|
||||
parser = optparse.OptionParser(description=description, prog='memfind',usage=usage)
|
||||
parser.add_option('-s', '--size', type='int', metavar='BYTESIZE', dest='size', help='Specify the byte size to search.', default=0)
|
||||
parser.add_option('--int8', action="callback", callback=append_data_callback, type='string', metavar='INT', dest='data', help='Specify a 8 bit signed integer value to search for in memory.', default='')
|
||||
parser.add_option('--int16', action="callback", callback=append_data_callback, type='string', metavar='INT', dest='data', help='Specify a 16 bit signed integer value to search for in memory.', default='')
|
||||
parser.add_option('--int32', action="callback", callback=append_data_callback, type='string', metavar='INT', dest='data', help='Specify a 32 bit signed integer value to search for in memory.', default='')
|
||||
parser.add_option('--int64', action="callback", callback=append_data_callback, type='string', metavar='INT', dest='data', help='Specify a 64 bit signed integer value to search for in memory.', default='')
|
||||
parser.add_option('--uint8', action="callback", callback=append_data_callback, type='string', metavar='INT', dest='data', help='Specify a 8 bit unsigned integer value to search for in memory.', default='')
|
||||
parser.add_option('--uint16', action="callback", callback=append_data_callback, type='string', metavar='INT', dest='data', help='Specify a 16 bit unsigned integer value to search for in memory.', default='')
|
||||
parser.add_option('--uint32', action="callback", callback=append_data_callback, type='string', metavar='INT', dest='data', help='Specify a 32 bit unsigned integer value to search for in memory.', default='')
|
||||
parser.add_option('--uint64', action="callback", callback=append_data_callback, type='string', metavar='INT', dest='data', help='Specify a 64 bit unsigned integer value to search for in memory.', default='')
|
||||
parser = optparse.OptionParser(
|
||||
description=description,
|
||||
prog='memfind',
|
||||
usage=usage)
|
||||
parser.add_option(
|
||||
'-s',
|
||||
'--size',
|
||||
type='int',
|
||||
metavar='BYTESIZE',
|
||||
dest='size',
|
||||
help='Specify the byte size to search.',
|
||||
default=0)
|
||||
parser.add_option(
|
||||
'--int8',
|
||||
action="callback",
|
||||
callback=append_data_callback,
|
||||
type='string',
|
||||
metavar='INT',
|
||||
dest='data',
|
||||
help='Specify a 8 bit signed integer value to search for in memory.',
|
||||
default='')
|
||||
parser.add_option(
|
||||
'--int16',
|
||||
action="callback",
|
||||
callback=append_data_callback,
|
||||
type='string',
|
||||
metavar='INT',
|
||||
dest='data',
|
||||
help='Specify a 16 bit signed integer value to search for in memory.',
|
||||
default='')
|
||||
parser.add_option(
|
||||
'--int32',
|
||||
action="callback",
|
||||
callback=append_data_callback,
|
||||
type='string',
|
||||
metavar='INT',
|
||||
dest='data',
|
||||
help='Specify a 32 bit signed integer value to search for in memory.',
|
||||
default='')
|
||||
parser.add_option(
|
||||
'--int64',
|
||||
action="callback",
|
||||
callback=append_data_callback,
|
||||
type='string',
|
||||
metavar='INT',
|
||||
dest='data',
|
||||
help='Specify a 64 bit signed integer value to search for in memory.',
|
||||
default='')
|
||||
parser.add_option(
|
||||
'--uint8',
|
||||
action="callback",
|
||||
callback=append_data_callback,
|
||||
type='string',
|
||||
metavar='INT',
|
||||
dest='data',
|
||||
help='Specify a 8 bit unsigned integer value to search for in memory.',
|
||||
default='')
|
||||
parser.add_option(
|
||||
'--uint16',
|
||||
action="callback",
|
||||
callback=append_data_callback,
|
||||
type='string',
|
||||
metavar='INT',
|
||||
dest='data',
|
||||
help='Specify a 16 bit unsigned integer value to search for in memory.',
|
||||
default='')
|
||||
parser.add_option(
|
||||
'--uint32',
|
||||
action="callback",
|
||||
callback=append_data_callback,
|
||||
type='string',
|
||||
metavar='INT',
|
||||
dest='data',
|
||||
help='Specify a 32 bit unsigned integer value to search for in memory.',
|
||||
default='')
|
||||
parser.add_option(
|
||||
'--uint64',
|
||||
action="callback",
|
||||
callback=append_data_callback,
|
||||
type='string',
|
||||
metavar='INT',
|
||||
dest='data',
|
||||
help='Specify a 64 bit unsigned integer value to search for in memory.',
|
||||
default='')
|
||||
return parser
|
||||
|
||||
def memfind_command (debugger, command, result, dict):
|
||||
# Use the Shell Lexer to properly parse up command options just like a
|
||||
|
||||
|
||||
def memfind_command(debugger, command, result, dict):
|
||||
# Use the Shell Lexer to properly parse up command options just like a
|
||||
# shell would
|
||||
command_args = shlex.split(command)
|
||||
parser = create_memfind_options()
|
||||
@@ -111,39 +193,49 @@ def memfind_command (debugger, command, result, dict):
|
||||
# result.SetStatus (lldb.eReturnStatusFailed)
|
||||
# print >>result, "error: option parsing failed" # returning a string is the same as returning an error whose description is the string
|
||||
# return
|
||||
memfind (debugger.GetSelectedTarget(), options, args, result)
|
||||
|
||||
memfind(debugger.GetSelectedTarget(), options, args, result)
|
||||
|
||||
|
||||
def print_error(str, show_usage, result):
|
||||
print >>result, str
|
||||
if show_usage:
|
||||
print >>result, create_memfind_options().format_help()
|
||||
|
||||
def memfind (target, options, args, result):
|
||||
|
||||
def memfind(target, options, args, result):
|
||||
num_args = len(args)
|
||||
start_addr = 0
|
||||
if num_args == 1:
|
||||
if options.size > 0:
|
||||
print_error ("error: --size must be specified if there is no ENDADDR argument", True, result)
|
||||
print_error(
|
||||
"error: --size must be specified if there is no ENDADDR argument",
|
||||
True,
|
||||
result)
|
||||
return
|
||||
start_addr = int(args[0], 0)
|
||||
elif num_args == 2:
|
||||
if options.size != 0:
|
||||
print_error ("error: --size can't be specified with an ENDADDR argument", True, result)
|
||||
print_error(
|
||||
"error: --size can't be specified with an ENDADDR argument",
|
||||
True,
|
||||
result)
|
||||
return
|
||||
start_addr = int(args[0], 0)
|
||||
end_addr = int(args[1], 0)
|
||||
if start_addr >= end_addr:
|
||||
print_error ("error: inavlid memory range [%#x - %#x)" % (start_addr, end_addr), True, result)
|
||||
print_error(
|
||||
"error: inavlid memory range [%#x - %#x)" %
|
||||
(start_addr, end_addr), True, result)
|
||||
return
|
||||
options.size = end_addr - start_addr
|
||||
else:
|
||||
print_error ("error: memfind takes 1 or 2 arguments", True, result)
|
||||
print_error("error: memfind takes 1 or 2 arguments", True, result)
|
||||
return
|
||||
|
||||
|
||||
if not options.data:
|
||||
print >>result, 'error: no data specified to search for'
|
||||
return
|
||||
|
||||
|
||||
if not target:
|
||||
print >>result, 'error: invalid target'
|
||||
return
|
||||
@@ -151,31 +243,34 @@ def memfind (target, options, args, result):
|
||||
if not process:
|
||||
print >>result, 'error: invalid process'
|
||||
return
|
||||
|
||||
|
||||
error = lldb.SBError()
|
||||
bytes = process.ReadMemory (start_addr, options.size, error)
|
||||
bytes = process.ReadMemory(start_addr, options.size, error)
|
||||
if error.Success():
|
||||
num_matches = 0
|
||||
print >>result, "Searching memory range [%#x - %#x) for" % (start_addr, end_addr),
|
||||
print >>result, "Searching memory range [%#x - %#x) for" % (
|
||||
start_addr, end_addr),
|
||||
for byte in options.data:
|
||||
print >>result, '%2.2x' % ord(byte),
|
||||
print >>result
|
||||
|
||||
|
||||
match_index = string.find(bytes, options.data)
|
||||
while match_index != -1:
|
||||
num_matches = num_matches + 1
|
||||
print >>result, '%#x: %#x + %u' % (start_addr + match_index, start_addr, match_index)
|
||||
print >>result, '%#x: %#x + %u' % (start_addr +
|
||||
match_index, start_addr, match_index)
|
||||
match_index = string.find(bytes, options.data, match_index + 1)
|
||||
|
||||
|
||||
if num_matches == 0:
|
||||
print >>result, "error: no matches found"
|
||||
else:
|
||||
print >>result, 'error: %s' % (error.GetCString())
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print 'error: this script is designed to be used within the embedded script interpreter in LLDB'
|
||||
elif getattr(lldb, 'debugger', None):
|
||||
memfind_command.__doc__ = create_memfind_options().format_help()
|
||||
lldb.debugger.HandleCommand('command script add -f memory.memfind_command memfind')
|
||||
lldb.debugger.HandleCommand(
|
||||
'command script add -f memory.memfind_command memfind')
|
||||
print '"memfind" command installed, use the "--help" option for detailed help'
|
||||
|
||||
@@ -3,21 +3,22 @@
|
||||
import lldb
|
||||
import struct
|
||||
|
||||
|
||||
class OperatingSystemPlugIn(object):
|
||||
"""Class that provides data for an instance of a LLDB 'OperatingSystemPython' plug-in class"""
|
||||
|
||||
|
||||
def __init__(self, process):
|
||||
'''Initialization needs a valid.SBProcess object.
|
||||
|
||||
|
||||
This plug-in will get created after a live process is valid and has stopped for the
|
||||
first time.'''
|
||||
self.process = None
|
||||
self.registers = None
|
||||
self.threads = None
|
||||
if type(process) is lldb.SBProcess and process.IsValid():
|
||||
if isinstance(process, lldb.SBProcess) and process.IsValid():
|
||||
self.process = process
|
||||
self.threads = None # Will be an dictionary containing info for each thread
|
||||
|
||||
self.threads = None # Will be an dictionary containing info for each thread
|
||||
|
||||
def get_target(self):
|
||||
# NOTE: Don't use "lldb.target" when trying to get your target as the "lldb.target"
|
||||
# tracks the current target in the LLDB command interpreter which isn't the
|
||||
@@ -26,11 +27,16 @@ class OperatingSystemPlugIn(object):
|
||||
|
||||
def create_thread(self, tid, context):
|
||||
if tid == 0x444444444:
|
||||
thread_info = { 'tid' : tid, 'name' : 'four' , 'queue' : 'queue4', 'state' : 'stopped', 'stop_reason' : 'none' }
|
||||
thread_info = {
|
||||
'tid': tid,
|
||||
'name': 'four',
|
||||
'queue': 'queue4',
|
||||
'state': 'stopped',
|
||||
'stop_reason': 'none'}
|
||||
self.threads.append(thread_info)
|
||||
return thread_info
|
||||
return None
|
||||
|
||||
|
||||
def get_thread_info(self):
|
||||
if not self.threads:
|
||||
# The sample dictionary below shows the values that can be returned for a thread
|
||||
@@ -48,57 +54,178 @@ class OperatingSystemPlugIn(object):
|
||||
# Specifying this key/value pair for a thread will avoid a call to get_register_data()
|
||||
# and can be used when your registers are in a thread context structure that is contiguous
|
||||
# in memory. Don't specify this if your register layout in memory doesn't match the layout
|
||||
# described by the dictionary returned from a call to the get_register_info() method.
|
||||
self.threads = [
|
||||
{ 'tid' : 0x111111111, 'name' : 'one' , 'queue' : 'queue1', 'state' : 'stopped', 'stop_reason' : 'breakpoint'},
|
||||
{ 'tid' : 0x222222222, 'name' : 'two' , 'queue' : 'queue2', 'state' : 'stopped', 'stop_reason' : 'none' },
|
||||
{ 'tid' : 0x333333333, 'name' : 'three', 'queue' : 'queue3', 'state' : 'stopped', 'stop_reason' : 'trace' , 'register_data_addr' : 0x100000000 }
|
||||
]
|
||||
# described by the dictionary returned from a call to the
|
||||
# get_register_info() method.
|
||||
self.threads = [{'tid': 0x111111111,
|
||||
'name': 'one',
|
||||
'queue': 'queue1',
|
||||
'state': 'stopped',
|
||||
'stop_reason': 'breakpoint'},
|
||||
{'tid': 0x222222222,
|
||||
'name': 'two',
|
||||
'queue': 'queue2',
|
||||
'state': 'stopped',
|
||||
'stop_reason': 'none'},
|
||||
{'tid': 0x333333333,
|
||||
'name': 'three',
|
||||
'queue': 'queue3',
|
||||
'state': 'stopped',
|
||||
'stop_reason': 'trace',
|
||||
'register_data_addr': 0x100000000}]
|
||||
return self.threads
|
||||
|
||||
|
||||
def get_register_info(self):
|
||||
if self.registers == None:
|
||||
self.registers = dict()
|
||||
if self.registers is None:
|
||||
self.registers = dict()
|
||||
triple = self.process.target.triple
|
||||
if triple:
|
||||
arch = triple.split('-')[0]
|
||||
if arch == 'x86_64':
|
||||
self.registers['sets'] = ['GPR', 'FPU', 'EXC']
|
||||
self.registers['registers'] = [
|
||||
{ 'name':'rax' , 'bitsize' : 64, 'offset' : 0, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 0, 'dwarf' : 0},
|
||||
{ 'name':'rbx' , 'bitsize' : 64, 'offset' : 8, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 3, 'dwarf' : 3},
|
||||
{ 'name':'rcx' , 'bitsize' : 64, 'offset' : 16, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 2, 'dwarf' : 2, 'generic':'arg4', 'alt-name':'arg4', },
|
||||
{ 'name':'rdx' , 'bitsize' : 64, 'offset' : 24, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 1, 'dwarf' : 1, 'generic':'arg3', 'alt-name':'arg3', },
|
||||
{ 'name':'rdi' , 'bitsize' : 64, 'offset' : 32, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 5, 'dwarf' : 5, 'generic':'arg1', 'alt-name':'arg1', },
|
||||
{ 'name':'rsi' , 'bitsize' : 64, 'offset' : 40, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 4, 'dwarf' : 4, 'generic':'arg2', 'alt-name':'arg2', },
|
||||
{ 'name':'rbp' , 'bitsize' : 64, 'offset' : 48, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 6, 'dwarf' : 6, 'generic':'fp' , 'alt-name':'fp', },
|
||||
{ 'name':'rsp' , 'bitsize' : 64, 'offset' : 56, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 7, 'dwarf' : 7, 'generic':'sp' , 'alt-name':'sp', },
|
||||
{ 'name':'r8' , 'bitsize' : 64, 'offset' : 64, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 8, 'dwarf' : 8, 'generic':'arg5', 'alt-name':'arg5', },
|
||||
{ 'name':'r9' , 'bitsize' : 64, 'offset' : 72, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 9, 'dwarf' : 9, 'generic':'arg6', 'alt-name':'arg6', },
|
||||
{ 'name':'r10' , 'bitsize' : 64, 'offset' : 80, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 10, 'dwarf' : 10},
|
||||
{ 'name':'r11' , 'bitsize' : 64, 'offset' : 88, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 11, 'dwarf' : 11},
|
||||
{ 'name':'r12' , 'bitsize' : 64, 'offset' : 96, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 12, 'dwarf' : 12},
|
||||
{ 'name':'r13' , 'bitsize' : 64, 'offset' : 104, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 13, 'dwarf' : 13},
|
||||
{ 'name':'r14' , 'bitsize' : 64, 'offset' : 112, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 14, 'dwarf' : 14},
|
||||
{ 'name':'r15' , 'bitsize' : 64, 'offset' : 120, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 15, 'dwarf' : 15},
|
||||
{ 'name':'rip' , 'bitsize' : 64, 'offset' : 128, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 16, 'dwarf' : 16, 'generic':'pc', 'alt-name':'pc' },
|
||||
{ 'name':'rflags' , 'bitsize' : 64, 'offset' : 136, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'generic':'flags', 'alt-name':'flags' },
|
||||
{ 'name':'cs' , 'bitsize' : 64, 'offset' : 144, 'encoding':'uint' , 'format':'hex' , 'set': 0 },
|
||||
{ 'name':'fs' , 'bitsize' : 64, 'offset' : 152, 'encoding':'uint' , 'format':'hex' , 'set': 0 },
|
||||
{ 'name':'gs' , 'bitsize' : 64, 'offset' : 160, 'encoding':'uint' , 'format':'hex' , 'set': 0 },
|
||||
]
|
||||
{'name': 'rax', 'bitsize': 64, 'offset': 0, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 0, 'dwarf': 0},
|
||||
{'name': 'rbx', 'bitsize': 64, 'offset': 8, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 3, 'dwarf': 3},
|
||||
{'name': 'rcx', 'bitsize': 64, 'offset': 16, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 2, 'dwarf': 2, 'generic': 'arg4', 'alt-name': 'arg4', },
|
||||
{'name': 'rdx', 'bitsize': 64, 'offset': 24, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 1, 'dwarf': 1, 'generic': 'arg3', 'alt-name': 'arg3', },
|
||||
{'name': 'rdi', 'bitsize': 64, 'offset': 32, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 5, 'dwarf': 5, 'generic': 'arg1', 'alt-name': 'arg1', },
|
||||
{'name': 'rsi', 'bitsize': 64, 'offset': 40, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 4, 'dwarf': 4, 'generic': 'arg2', 'alt-name': 'arg2', },
|
||||
{'name': 'rbp', 'bitsize': 64, 'offset': 48, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 6, 'dwarf': 6, 'generic': 'fp', 'alt-name': 'fp', },
|
||||
{'name': 'rsp', 'bitsize': 64, 'offset': 56, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 7, 'dwarf': 7, 'generic': 'sp', 'alt-name': 'sp', },
|
||||
{'name': 'r8', 'bitsize': 64, 'offset': 64, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 8, 'dwarf': 8, 'generic': 'arg5', 'alt-name': 'arg5', },
|
||||
{'name': 'r9', 'bitsize': 64, 'offset': 72, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 9, 'dwarf': 9, 'generic': 'arg6', 'alt-name': 'arg6', },
|
||||
{'name': 'r10', 'bitsize': 64, 'offset': 80, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 10, 'dwarf': 10},
|
||||
{'name': 'r11', 'bitsize': 64, 'offset': 88, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 11, 'dwarf': 11},
|
||||
{'name': 'r12', 'bitsize': 64, 'offset': 96, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 12, 'dwarf': 12},
|
||||
{'name': 'r13', 'bitsize': 64, 'offset': 104, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 13, 'dwarf': 13},
|
||||
{'name': 'r14', 'bitsize': 64, 'offset': 112, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 14, 'dwarf': 14},
|
||||
{'name': 'r15', 'bitsize': 64, 'offset': 120, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 15, 'dwarf': 15},
|
||||
{'name': 'rip', 'bitsize': 64, 'offset': 128, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 16, 'dwarf': 16, 'generic': 'pc', 'alt-name': 'pc'},
|
||||
{'name': 'rflags', 'bitsize': 64, 'offset': 136, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'generic': 'flags', 'alt-name': 'flags'},
|
||||
{'name': 'cs', 'bitsize': 64, 'offset': 144, 'encoding': 'uint', 'format': 'hex', 'set': 0},
|
||||
{'name': 'fs', 'bitsize': 64, 'offset': 152, 'encoding': 'uint', 'format': 'hex', 'set': 0},
|
||||
{'name': 'gs', 'bitsize': 64, 'offset': 160, 'encoding': 'uint', 'format': 'hex', 'set': 0},
|
||||
]
|
||||
return self.registers
|
||||
|
||||
|
||||
def get_register_data(self, tid):
|
||||
if tid == 0x111111111:
|
||||
return struct.pack('21Q',1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21);
|
||||
return struct.pack(
|
||||
'21Q',
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
10,
|
||||
11,
|
||||
12,
|
||||
13,
|
||||
14,
|
||||
15,
|
||||
16,
|
||||
17,
|
||||
18,
|
||||
19,
|
||||
20,
|
||||
21)
|
||||
elif tid == 0x222222222:
|
||||
return struct.pack('21Q',11,12,13,14,15,16,17,18,19,110,111,112,113,114,115,116,117,118,119,120,121);
|
||||
return struct.pack(
|
||||
'21Q',
|
||||
11,
|
||||
12,
|
||||
13,
|
||||
14,
|
||||
15,
|
||||
16,
|
||||
17,
|
||||
18,
|
||||
19,
|
||||
110,
|
||||
111,
|
||||
112,
|
||||
113,
|
||||
114,
|
||||
115,
|
||||
116,
|
||||
117,
|
||||
118,
|
||||
119,
|
||||
120,
|
||||
121)
|
||||
elif tid == 0x333333333:
|
||||
return struct.pack('21Q',21,22,23,24,25,26,27,28,29,210,211,212,213,214,215,216,217,218,219,220,221);
|
||||
return struct.pack(
|
||||
'21Q',
|
||||
21,
|
||||
22,
|
||||
23,
|
||||
24,
|
||||
25,
|
||||
26,
|
||||
27,
|
||||
28,
|
||||
29,
|
||||
210,
|
||||
211,
|
||||
212,
|
||||
213,
|
||||
214,
|
||||
215,
|
||||
216,
|
||||
217,
|
||||
218,
|
||||
219,
|
||||
220,
|
||||
221)
|
||||
elif tid == 0x444444444:
|
||||
return struct.pack('21Q',31,32,33,34,35,36,37,38,39,310,311,312,313,314,315,316,317,318,319,320,321);
|
||||
return struct.pack(
|
||||
'21Q',
|
||||
31,
|
||||
32,
|
||||
33,
|
||||
34,
|
||||
35,
|
||||
36,
|
||||
37,
|
||||
38,
|
||||
39,
|
||||
310,
|
||||
311,
|
||||
312,
|
||||
313,
|
||||
314,
|
||||
315,
|
||||
316,
|
||||
317,
|
||||
318,
|
||||
319,
|
||||
320,
|
||||
321)
|
||||
else:
|
||||
return struct.pack('21Q',41,42,43,44,45,46,47,48,49,410,411,412,413,414,415,416,417,418,419,420,421);
|
||||
return struct.pack(
|
||||
'21Q',
|
||||
41,
|
||||
42,
|
||||
43,
|
||||
44,
|
||||
45,
|
||||
46,
|
||||
47,
|
||||
48,
|
||||
49,
|
||||
410,
|
||||
411,
|
||||
412,
|
||||
413,
|
||||
414,
|
||||
415,
|
||||
416,
|
||||
417,
|
||||
418,
|
||||
419,
|
||||
420,
|
||||
421)
|
||||
return None
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ import types
|
||||
#----------------------------------------------------------------------
|
||||
# Code that auto imports LLDB
|
||||
#----------------------------------------------------------------------
|
||||
try:
|
||||
try:
|
||||
# Just try for LLDB in case PYTHONPATH is already correctly setup
|
||||
import lldb
|
||||
except ImportError:
|
||||
@@ -32,15 +32,20 @@ except ImportError:
|
||||
# On Darwin, try the currently selected Xcode directory
|
||||
xcode_dir = commands.getoutput("xcode-select --print-path")
|
||||
if xcode_dir:
|
||||
lldb_python_dirs.append(os.path.realpath(xcode_dir + '/../SharedFrameworks/LLDB.framework/Resources/Python'))
|
||||
lldb_python_dirs.append(xcode_dir + '/Library/PrivateFrameworks/LLDB.framework/Resources/Python')
|
||||
lldb_python_dirs.append('/System/Library/PrivateFrameworks/LLDB.framework/Resources/Python')
|
||||
lldb_python_dirs.append(
|
||||
os.path.realpath(
|
||||
xcode_dir +
|
||||
'/../SharedFrameworks/LLDB.framework/Resources/Python'))
|
||||
lldb_python_dirs.append(
|
||||
xcode_dir + '/Library/PrivateFrameworks/LLDB.framework/Resources/Python')
|
||||
lldb_python_dirs.append(
|
||||
'/System/Library/PrivateFrameworks/LLDB.framework/Resources/Python')
|
||||
success = False
|
||||
for lldb_python_dir in lldb_python_dirs:
|
||||
if os.path.exists(lldb_python_dir):
|
||||
if not (sys.path.__contains__(lldb_python_dir)):
|
||||
sys.path.append(lldb_python_dir)
|
||||
try:
|
||||
try:
|
||||
import lldb
|
||||
except ImportError:
|
||||
pass
|
||||
@@ -53,7 +58,8 @@ except ImportError:
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
class Timer:
|
||||
class Timer:
|
||||
|
||||
def __enter__(self):
|
||||
self.start = time.clock()
|
||||
return self
|
||||
@@ -62,30 +68,45 @@ class Timer:
|
||||
self.end = time.clock()
|
||||
self.interval = self.end - self.start
|
||||
|
||||
|
||||
class Action(object):
|
||||
"""Class that encapsulates actions to take when a thread stops for a reason."""
|
||||
def __init__(self, callback = None, callback_owner = None):
|
||||
|
||||
def __init__(self, callback=None, callback_owner=None):
|
||||
self.callback = callback
|
||||
self.callback_owner = callback_owner
|
||||
def ThreadStopped (self, thread):
|
||||
|
||||
def ThreadStopped(self, thread):
|
||||
assert False, "performance.Action.ThreadStopped(self, thread) must be overridden in a subclass"
|
||||
|
||||
|
||||
class PlanCompleteAction (Action):
|
||||
def __init__(self, callback = None, callback_owner = None):
|
||||
|
||||
def __init__(self, callback=None, callback_owner=None):
|
||||
Action.__init__(self, callback, callback_owner)
|
||||
def ThreadStopped (self, thread):
|
||||
|
||||
def ThreadStopped(self, thread):
|
||||
if thread.GetStopReason() == lldb.eStopReasonPlanComplete:
|
||||
if self.callback:
|
||||
if self.callback_owner:
|
||||
self.callback (self.callback_owner, thread)
|
||||
self.callback(self.callback_owner, thread)
|
||||
else:
|
||||
self.callback (thread)
|
||||
self.callback(thread)
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
class BreakpointAction (Action):
|
||||
def __init__(self, callback = None, callback_owner = None, name = None, module = None, file = None, line = None, breakpoint = None):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
callback=None,
|
||||
callback_owner=None,
|
||||
name=None,
|
||||
module=None,
|
||||
file=None,
|
||||
line=None,
|
||||
breakpoint=None):
|
||||
Action.__init__(self, callback, callback_owner)
|
||||
self.modules = lldb.SBFileSpecList()
|
||||
self.files = lldb.SBFileSpecList()
|
||||
@@ -97,7 +118,8 @@ class BreakpointAction (Action):
|
||||
if module:
|
||||
if isinstance(module, types.ListType):
|
||||
for module_path in module:
|
||||
self.modules.Append(lldb.SBFileSpec(module_path, False))
|
||||
self.modules.Append(
|
||||
lldb.SBFileSpec(module_path, False))
|
||||
elif isinstance(module, types.StringTypes):
|
||||
self.modules.Append(lldb.SBFileSpec(module, False))
|
||||
if name:
|
||||
@@ -109,22 +131,30 @@ class BreakpointAction (Action):
|
||||
self.files.Append(lldb.SBFileSpec(f, False))
|
||||
elif isinstance(file, types.StringTypes):
|
||||
self.files.Append(lldb.SBFileSpec(file, False))
|
||||
self.breakpoints.append (self.target.BreakpointCreateByName(name, self.modules, self.files))
|
||||
self.breakpoints.append(
|
||||
self.target.BreakpointCreateByName(
|
||||
name, self.modules, self.files))
|
||||
elif file and line:
|
||||
self.breakpoints.append (self.target.BreakpointCreateByLocation(file, line))
|
||||
def ThreadStopped (self, thread):
|
||||
self.breakpoints.append(
|
||||
self.target.BreakpointCreateByLocation(
|
||||
file, line))
|
||||
|
||||
def ThreadStopped(self, thread):
|
||||
if thread.GetStopReason() == lldb.eStopReasonBreakpoint:
|
||||
for bp in self.breakpoints:
|
||||
if bp.GetID() == thread.GetStopReasonDataAtIndex(0):
|
||||
if self.callback:
|
||||
if self.callback_owner:
|
||||
self.callback (self.callback_owner, thread)
|
||||
self.callback(self.callback_owner, thread)
|
||||
else:
|
||||
self.callback (thread)
|
||||
self.callback(thread)
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
class TestCase:
|
||||
"""Class that aids in running performance tests."""
|
||||
|
||||
def __init__(self):
|
||||
self.verbose = False
|
||||
self.debugger = lldb.SBDebugger.Create()
|
||||
@@ -137,36 +167,37 @@ class TestCase:
|
||||
self.user_actions = list()
|
||||
self.builtin_actions = list()
|
||||
self.bp_id_to_dict = dict()
|
||||
|
||||
|
||||
def Setup(self, args):
|
||||
self.launch_info = lldb.SBLaunchInfo(args)
|
||||
|
||||
def Run (self, args):
|
||||
|
||||
def Run(self, args):
|
||||
assert False, "performance.TestCase.Run(self, args) must be subclassed"
|
||||
|
||||
|
||||
def Launch(self):
|
||||
if self.target:
|
||||
error = lldb.SBError()
|
||||
self.process = self.target.Launch (self.launch_info, error)
|
||||
self.process = self.target.Launch(self.launch_info, error)
|
||||
if not error.Success():
|
||||
print "error: %s" % error.GetCString()
|
||||
if self.process:
|
||||
self.process.GetBroadcaster().AddListener(self.listener, lldb.SBProcess.eBroadcastBitStateChanged | lldb.SBProcess.eBroadcastBitInterrupt)
|
||||
self.process.GetBroadcaster().AddListener(self.listener,
|
||||
lldb.SBProcess.eBroadcastBitStateChanged | lldb.SBProcess.eBroadcastBitInterrupt)
|
||||
return True
|
||||
return False
|
||||
|
||||
def WaitForNextProcessEvent (self):
|
||||
|
||||
def WaitForNextProcessEvent(self):
|
||||
event = None
|
||||
if self.process:
|
||||
while event is None:
|
||||
process_event = lldb.SBEvent()
|
||||
if self.listener.WaitForEvent (lldb.UINT32_MAX, process_event):
|
||||
state = lldb.SBProcess.GetStateFromEvent (process_event)
|
||||
if self.listener.WaitForEvent(lldb.UINT32_MAX, process_event):
|
||||
state = lldb.SBProcess.GetStateFromEvent(process_event)
|
||||
if self.verbose:
|
||||
print "event = %s" % (lldb.SBDebugger.StateAsCString(state))
|
||||
if lldb.SBProcess.GetRestartedFromEvent(process_event):
|
||||
continue
|
||||
if state == lldb.eStateInvalid or state == lldb.eStateDetached or state == lldb.eStateCrashed or state == lldb.eStateUnloaded or state == lldb.eStateExited:
|
||||
if state == lldb.eStateInvalid or state == lldb.eStateDetached or state == lldb.eStateCrashed or state == lldb.eStateUnloaded or state == lldb.eStateExited:
|
||||
event = process_event
|
||||
self.done = True
|
||||
elif state == lldb.eStateConnected or state == lldb.eStateAttaching or state == lldb.eStateLaunching or state == lldb.eStateRunning or state == lldb.eStateStepping or state == lldb.eStateSuspended:
|
||||
@@ -179,10 +210,10 @@ class TestCase:
|
||||
for thread in self.process:
|
||||
frame = thread.GetFrameAtIndex(0)
|
||||
select_thread = False
|
||||
|
||||
|
||||
stop_reason = thread.GetStopReason()
|
||||
if self.verbose:
|
||||
print "tid = %#x pc = %#x " % (thread.GetThreadID(),frame.GetPC()),
|
||||
print "tid = %#x pc = %#x " % (thread.GetThreadID(), frame.GetPC()),
|
||||
if stop_reason == lldb.eStopReasonNone:
|
||||
if self.verbose:
|
||||
print "none"
|
||||
@@ -222,37 +253,53 @@ class TestCase:
|
||||
select_thread = True
|
||||
if self.verbose:
|
||||
print "signal %d" % (thread.GetStopReasonDataAtIndex(0))
|
||||
|
||||
|
||||
if select_thread and not selected_thread:
|
||||
self.thread = thread
|
||||
selected_thread = self.process.SetSelectedThread(thread)
|
||||
|
||||
selected_thread = self.process.SetSelectedThread(
|
||||
thread)
|
||||
|
||||
for action in self.user_actions:
|
||||
action.ThreadStopped (thread)
|
||||
|
||||
action.ThreadStopped(thread)
|
||||
|
||||
if fatal:
|
||||
# if self.verbose:
|
||||
# if self.verbose:
|
||||
# Xcode.RunCommand(self.debugger,"bt all",true)
|
||||
sys.exit(1)
|
||||
return event
|
||||
|
||||
|
||||
|
||||
class Measurement:
|
||||
'''A class that encapsulates a measurement'''
|
||||
|
||||
def __init__(self):
|
||||
object.__init__(self)
|
||||
|
||||
def Measure(self):
|
||||
assert False, "performance.Measurement.Measure() must be subclassed"
|
||||
|
||||
|
||||
|
||||
class MemoryMeasurement(Measurement):
|
||||
'''A class that can measure memory statistics for a process.'''
|
||||
|
||||
def __init__(self, pid):
|
||||
Measurement.__init__(self)
|
||||
self.pid = pid
|
||||
self.stats = ["rprvt","rshrd","rsize","vsize","vprvt","kprvt","kshrd","faults","cow","pageins"]
|
||||
self.command = "top -l 1 -pid %u -stats %s" % (self.pid, ",".join(self.stats))
|
||||
self.stats = [
|
||||
"rprvt",
|
||||
"rshrd",
|
||||
"rsize",
|
||||
"vsize",
|
||||
"vprvt",
|
||||
"kprvt",
|
||||
"kshrd",
|
||||
"faults",
|
||||
"cow",
|
||||
"pageins"]
|
||||
self.command = "top -l 1 -pid %u -stats %s" % (
|
||||
self.pid, ",".join(self.stats))
|
||||
self.value = dict()
|
||||
|
||||
|
||||
def Measure(self):
|
||||
output = commands.getoutput(self.command).split("\n")[-1]
|
||||
values = re.split('[-+\s]+', output)
|
||||
@@ -263,14 +310,14 @@ class MemoryMeasurement(Measurement):
|
||||
multiplier = 1024
|
||||
stat = stat[:-1]
|
||||
elif stat[-1] == 'M':
|
||||
multiplier = 1024*1024
|
||||
multiplier = 1024 * 1024
|
||||
stat = stat[:-1]
|
||||
elif stat[-1] == 'G':
|
||||
multiplier = 1024*1024*1024
|
||||
multiplier = 1024 * 1024 * 1024
|
||||
elif stat[-1] == 'T':
|
||||
multiplier = 1024*1024*1024*1024
|
||||
multiplier = 1024 * 1024 * 1024 * 1024
|
||||
stat = stat[:-1]
|
||||
self.value[self.stats[idx]] = int (stat) * multiplier
|
||||
self.value[self.stats[idx]] = int(stat) * multiplier
|
||||
|
||||
def __str__(self):
|
||||
'''Dump the MemoryMeasurement current value'''
|
||||
@@ -282,37 +329,47 @@ class MemoryMeasurement(Measurement):
|
||||
return s
|
||||
|
||||
|
||||
class TesterTestCase(TestCase):
|
||||
class TesterTestCase(TestCase):
|
||||
|
||||
def __init__(self):
|
||||
TestCase.__init__(self)
|
||||
self.verbose = True
|
||||
self.num_steps = 5
|
||||
|
||||
def BreakpointHit (self, thread):
|
||||
|
||||
def BreakpointHit(self, thread):
|
||||
bp_id = thread.GetStopReasonDataAtIndex(0)
|
||||
loc_id = thread.GetStopReasonDataAtIndex(1)
|
||||
print "Breakpoint %i.%i hit: %s" % (bp_id, loc_id, thread.process.target.FindBreakpointByID(bp_id))
|
||||
thread.StepOver()
|
||||
|
||||
def PlanComplete (self, thread):
|
||||
|
||||
def PlanComplete(self, thread):
|
||||
if self.num_steps > 0:
|
||||
thread.StepOver()
|
||||
self.num_steps = self.num_steps - 1
|
||||
else:
|
||||
thread.process.Kill()
|
||||
|
||||
def Run (self, args):
|
||||
def Run(self, args):
|
||||
self.Setup(args)
|
||||
with Timer() as total_time:
|
||||
self.target = self.debugger.CreateTarget(args[0])
|
||||
if self.target:
|
||||
with Timer() as breakpoint_timer:
|
||||
bp = self.target.BreakpointCreateByName("main")
|
||||
print('Breakpoint time = %.03f sec.' % breakpoint_timer.interval)
|
||||
|
||||
self.user_actions.append (BreakpointAction(breakpoint=bp, callback=TesterTestCase.BreakpointHit, callback_owner=self))
|
||||
self.user_actions.append (PlanCompleteAction(callback=TesterTestCase.PlanComplete, callback_owner=self))
|
||||
|
||||
print(
|
||||
'Breakpoint time = %.03f sec.' %
|
||||
breakpoint_timer.interval)
|
||||
|
||||
self.user_actions.append(
|
||||
BreakpointAction(
|
||||
breakpoint=bp,
|
||||
callback=TesterTestCase.BreakpointHit,
|
||||
callback_owner=self))
|
||||
self.user_actions.append(
|
||||
PlanCompleteAction(
|
||||
callback=TesterTestCase.PlanComplete,
|
||||
callback_owner=self))
|
||||
|
||||
if self.Launch():
|
||||
while not self.done:
|
||||
self.WaitForNextProcessEvent()
|
||||
@@ -321,12 +378,12 @@ class TesterTestCase(TestCase):
|
||||
else:
|
||||
print "error: failed to create target with '%s'" % (args[0])
|
||||
print('Total time = %.03f sec.' % total_time.interval)
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
lldb.SBDebugger.Initialize()
|
||||
test = TesterTestCase()
|
||||
test.Run (sys.argv[1:])
|
||||
test.Run(sys.argv[1:])
|
||||
mem = MemoryMeasurement(os.getpid())
|
||||
mem.Measure()
|
||||
print str(mem)
|
||||
|
||||
@@ -17,7 +17,7 @@ import sys
|
||||
#----------------------------------------------------------------------
|
||||
# Code that auto imports LLDB
|
||||
#----------------------------------------------------------------------
|
||||
try:
|
||||
try:
|
||||
# Just try for LLDB in case PYTHONPATH is already correctly setup
|
||||
import lldb
|
||||
except ImportError:
|
||||
@@ -28,15 +28,20 @@ except ImportError:
|
||||
# On Darwin, try the currently selected Xcode directory
|
||||
xcode_dir = commands.getoutput("xcode-select --print-path")
|
||||
if xcode_dir:
|
||||
lldb_python_dirs.append(os.path.realpath(xcode_dir + '/../SharedFrameworks/LLDB.framework/Resources/Python'))
|
||||
lldb_python_dirs.append(xcode_dir + '/Library/PrivateFrameworks/LLDB.framework/Resources/Python')
|
||||
lldb_python_dirs.append('/System/Library/PrivateFrameworks/LLDB.framework/Resources/Python')
|
||||
lldb_python_dirs.append(
|
||||
os.path.realpath(
|
||||
xcode_dir +
|
||||
'/../SharedFrameworks/LLDB.framework/Resources/Python'))
|
||||
lldb_python_dirs.append(
|
||||
xcode_dir + '/Library/PrivateFrameworks/LLDB.framework/Resources/Python')
|
||||
lldb_python_dirs.append(
|
||||
'/System/Library/PrivateFrameworks/LLDB.framework/Resources/Python')
|
||||
success = False
|
||||
for lldb_python_dir in lldb_python_dirs:
|
||||
if os.path.exists(lldb_python_dir):
|
||||
if not (sys.path.__contains__(lldb_python_dir)):
|
||||
sys.path.append(lldb_python_dir)
|
||||
try:
|
||||
try:
|
||||
import lldb
|
||||
except ImportError:
|
||||
pass
|
||||
@@ -48,117 +53,241 @@ except ImportError:
|
||||
print "error: couldn't locate the 'lldb' module, please set PYTHONPATH correctly"
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def print_threads(process, options):
|
||||
if options.show_threads:
|
||||
for thread in process:
|
||||
print '%s %s' % (thread, thread.GetFrameAtIndex(0))
|
||||
|
||||
|
||||
def run_commands(command_interpreter, commands):
|
||||
return_obj = lldb.SBCommandReturnObject()
|
||||
for command in commands:
|
||||
command_interpreter.HandleCommand( command, return_obj )
|
||||
command_interpreter.HandleCommand(command, return_obj)
|
||||
if return_obj.Succeeded():
|
||||
print return_obj.GetOutput()
|
||||
else:
|
||||
print return_obj
|
||||
if options.stop_on_error:
|
||||
break
|
||||
|
||||
|
||||
|
||||
def main(argv):
|
||||
description='''Debugs a program using the LLDB python API and uses asynchronous broadcast events to watch for process state changes.'''
|
||||
epilog='''Examples:
|
||||
description = '''Debugs a program using the LLDB python API and uses asynchronous broadcast events to watch for process state changes.'''
|
||||
epilog = '''Examples:
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
# Run "/bin/ls" with the arguments "-lAF /tmp/", and set a breakpoint
|
||||
# Run "/bin/ls" with the arguments "-lAF /tmp/", and set a breakpoint
|
||||
# at "malloc" and backtrace and read all registers each time we stop
|
||||
#----------------------------------------------------------------------
|
||||
% ./process_events.py --breakpoint malloc --stop-command bt --stop-command 'register read' -- /bin/ls -lAF /tmp/
|
||||
|
||||
'''
|
||||
optparse.OptionParser.format_epilog = lambda self, formatter: self.epilog
|
||||
parser = optparse.OptionParser(description=description, prog='process_events',usage='usage: process_events [options] program [arg1 arg2]', epilog=epilog)
|
||||
parser.add_option('-v', '--verbose', action='store_true', dest='verbose', help="Enable verbose logging.", default=False)
|
||||
parser.add_option('-b', '--breakpoint', action='append', type='string', metavar='BPEXPR', dest='breakpoints', help='Breakpoint commands to create after the target has been created, the values will be sent to the "_regexp-break" command which supports breakpoints by name, file:line, and address.')
|
||||
parser.add_option('-a', '--arch', type='string', dest='arch', help='The architecture to use when creating the debug target.', default=None)
|
||||
parser.add_option('--platform', type='string', metavar='platform', dest='platform', help='Specify the platform to use when creating the debug target. Valid values include "localhost", "darwin-kernel", "ios-simulator", "remote-freebsd", "remote-macosx", "remote-ios", "remote-linux".', default=None)
|
||||
parser.add_option('-l', '--launch-command', action='append', type='string', metavar='CMD', dest='launch_commands', help='LLDB command interpreter commands to run once after the process has launched. This option can be specified more than once.', default=[])
|
||||
parser.add_option('-s', '--stop-command', action='append', type='string', metavar='CMD', dest='stop_commands', help='LLDB command interpreter commands to run each time the process stops. This option can be specified more than once.', default=[])
|
||||
parser.add_option('-c', '--crash-command', action='append', type='string', metavar='CMD', dest='crash_commands', help='LLDB command interpreter commands to run in case the process crashes. This option can be specified more than once.', default=[])
|
||||
parser.add_option('-x', '--exit-command', action='append', type='string', metavar='CMD', dest='exit_commands', help='LLDB command interpreter commands to run once after the process has exited. This option can be specified more than once.', default=[])
|
||||
parser.add_option('-T', '--no-threads', action='store_false', dest='show_threads', help="Don't show threads when process stops.", default=True)
|
||||
parser.add_option('--ignore-errors', action='store_false', dest='stop_on_error', help="Don't stop executing LLDB commands if the command returns an error. This applies to all of the LLDB command interpreter commands that get run for launch, stop, crash and exit.", default=True)
|
||||
parser.add_option('-n', '--run-count', type='int', dest='run_count', metavar='N', help='How many times to run the process in case the process exits.', default=1)
|
||||
parser.add_option('-t', '--event-timeout', type='int', dest='event_timeout', metavar='SEC', help='Specify the timeout in seconds to wait for process state change events.', default=lldb.UINT32_MAX)
|
||||
parser.add_option('-e', '--environment', action='append', type='string', metavar='ENV', dest='env_vars', help='Environment variables to set in the inferior process when launching a process.')
|
||||
parser.add_option('-d', '--working-dir', type='string', metavar='DIR', dest='working_dir', help='The the current working directory when launching a process.', default=None)
|
||||
parser.add_option('-p', '--attach-pid', type='int', dest='attach_pid', metavar='PID', help='Specify a process to attach to by process ID.', default=-1)
|
||||
parser.add_option('-P', '--attach-name', type='string', dest='attach_name', metavar='PROCESSNAME', help='Specify a process to attach to by name.', default=None)
|
||||
parser.add_option('-w', '--attach-wait', action='store_true', dest='attach_wait', help='Wait for the next process to launch when attaching to a process by name.', default=False)
|
||||
parser = optparse.OptionParser(
|
||||
description=description,
|
||||
prog='process_events',
|
||||
usage='usage: process_events [options] program [arg1 arg2]',
|
||||
epilog=epilog)
|
||||
parser.add_option(
|
||||
'-v',
|
||||
'--verbose',
|
||||
action='store_true',
|
||||
dest='verbose',
|
||||
help="Enable verbose logging.",
|
||||
default=False)
|
||||
parser.add_option(
|
||||
'-b',
|
||||
'--breakpoint',
|
||||
action='append',
|
||||
type='string',
|
||||
metavar='BPEXPR',
|
||||
dest='breakpoints',
|
||||
help='Breakpoint commands to create after the target has been created, the values will be sent to the "_regexp-break" command which supports breakpoints by name, file:line, and address.')
|
||||
parser.add_option(
|
||||
'-a',
|
||||
'--arch',
|
||||
type='string',
|
||||
dest='arch',
|
||||
help='The architecture to use when creating the debug target.',
|
||||
default=None)
|
||||
parser.add_option(
|
||||
'--platform',
|
||||
type='string',
|
||||
metavar='platform',
|
||||
dest='platform',
|
||||
help='Specify the platform to use when creating the debug target. Valid values include "localhost", "darwin-kernel", "ios-simulator", "remote-freebsd", "remote-macosx", "remote-ios", "remote-linux".',
|
||||
default=None)
|
||||
parser.add_option(
|
||||
'-l',
|
||||
'--launch-command',
|
||||
action='append',
|
||||
type='string',
|
||||
metavar='CMD',
|
||||
dest='launch_commands',
|
||||
help='LLDB command interpreter commands to run once after the process has launched. This option can be specified more than once.',
|
||||
default=[])
|
||||
parser.add_option(
|
||||
'-s',
|
||||
'--stop-command',
|
||||
action='append',
|
||||
type='string',
|
||||
metavar='CMD',
|
||||
dest='stop_commands',
|
||||
help='LLDB command interpreter commands to run each time the process stops. This option can be specified more than once.',
|
||||
default=[])
|
||||
parser.add_option(
|
||||
'-c',
|
||||
'--crash-command',
|
||||
action='append',
|
||||
type='string',
|
||||
metavar='CMD',
|
||||
dest='crash_commands',
|
||||
help='LLDB command interpreter commands to run in case the process crashes. This option can be specified more than once.',
|
||||
default=[])
|
||||
parser.add_option(
|
||||
'-x',
|
||||
'--exit-command',
|
||||
action='append',
|
||||
type='string',
|
||||
metavar='CMD',
|
||||
dest='exit_commands',
|
||||
help='LLDB command interpreter commands to run once after the process has exited. This option can be specified more than once.',
|
||||
default=[])
|
||||
parser.add_option(
|
||||
'-T',
|
||||
'--no-threads',
|
||||
action='store_false',
|
||||
dest='show_threads',
|
||||
help="Don't show threads when process stops.",
|
||||
default=True)
|
||||
parser.add_option(
|
||||
'--ignore-errors',
|
||||
action='store_false',
|
||||
dest='stop_on_error',
|
||||
help="Don't stop executing LLDB commands if the command returns an error. This applies to all of the LLDB command interpreter commands that get run for launch, stop, crash and exit.",
|
||||
default=True)
|
||||
parser.add_option(
|
||||
'-n',
|
||||
'--run-count',
|
||||
type='int',
|
||||
dest='run_count',
|
||||
metavar='N',
|
||||
help='How many times to run the process in case the process exits.',
|
||||
default=1)
|
||||
parser.add_option(
|
||||
'-t',
|
||||
'--event-timeout',
|
||||
type='int',
|
||||
dest='event_timeout',
|
||||
metavar='SEC',
|
||||
help='Specify the timeout in seconds to wait for process state change events.',
|
||||
default=lldb.UINT32_MAX)
|
||||
parser.add_option(
|
||||
'-e',
|
||||
'--environment',
|
||||
action='append',
|
||||
type='string',
|
||||
metavar='ENV',
|
||||
dest='env_vars',
|
||||
help='Environment variables to set in the inferior process when launching a process.')
|
||||
parser.add_option(
|
||||
'-d',
|
||||
'--working-dir',
|
||||
type='string',
|
||||
metavar='DIR',
|
||||
dest='working_dir',
|
||||
help='The the current working directory when launching a process.',
|
||||
default=None)
|
||||
parser.add_option(
|
||||
'-p',
|
||||
'--attach-pid',
|
||||
type='int',
|
||||
dest='attach_pid',
|
||||
metavar='PID',
|
||||
help='Specify a process to attach to by process ID.',
|
||||
default=-1)
|
||||
parser.add_option(
|
||||
'-P',
|
||||
'--attach-name',
|
||||
type='string',
|
||||
dest='attach_name',
|
||||
metavar='PROCESSNAME',
|
||||
help='Specify a process to attach to by name.',
|
||||
default=None)
|
||||
parser.add_option(
|
||||
'-w',
|
||||
'--attach-wait',
|
||||
action='store_true',
|
||||
dest='attach_wait',
|
||||
help='Wait for the next process to launch when attaching to a process by name.',
|
||||
default=False)
|
||||
try:
|
||||
(options, args) = parser.parse_args(argv)
|
||||
except:
|
||||
return
|
||||
|
||||
|
||||
attach_info = None
|
||||
launch_info = None
|
||||
exe = None
|
||||
if args:
|
||||
exe = args.pop(0)
|
||||
launch_info = lldb.SBLaunchInfo (args)
|
||||
launch_info = lldb.SBLaunchInfo(args)
|
||||
if options.env_vars:
|
||||
launch_info.SetEnvironmentEntries(options.env_vars, True)
|
||||
if options.working_dir:
|
||||
launch_info.SetWorkingDirectory(options.working_dir)
|
||||
elif options.attach_pid != -1:
|
||||
if options.run_count == 1:
|
||||
attach_info = lldb.SBAttachInfo (options.attach_pid)
|
||||
attach_info = lldb.SBAttachInfo(options.attach_pid)
|
||||
else:
|
||||
print "error: --run-count can't be used with the --attach-pid option"
|
||||
sys.exit(1)
|
||||
elif not options.attach_name is None:
|
||||
if options.run_count == 1:
|
||||
attach_info = lldb.SBAttachInfo (options.attach_name, options.attach_wait)
|
||||
attach_info = lldb.SBAttachInfo(
|
||||
options.attach_name, options.attach_wait)
|
||||
else:
|
||||
print "error: --run-count can't be used with the --attach-name option"
|
||||
sys.exit(1)
|
||||
else:
|
||||
print 'error: a program path for a program to debug and its arguments are required'
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
|
||||
# Create a new debugger instance
|
||||
debugger = lldb.SBDebugger.Create()
|
||||
debugger.SetAsync (True)
|
||||
debugger.SetAsync(True)
|
||||
command_interpreter = debugger.GetCommandInterpreter()
|
||||
# Create a target from a file and arch
|
||||
|
||||
|
||||
if exe:
|
||||
print "Creating a target for '%s'" % exe
|
||||
error = lldb.SBError()
|
||||
target = debugger.CreateTarget (exe, options.arch, options.platform, True, error)
|
||||
|
||||
target = debugger.CreateTarget(
|
||||
exe, options.arch, options.platform, True, error)
|
||||
|
||||
if target:
|
||||
|
||||
|
||||
# Set any breakpoints that were specified in the args if we are launching. We use the
|
||||
# command line command to take advantage of the shorthand breakpoint creation
|
||||
# command line command to take advantage of the shorthand breakpoint
|
||||
# creation
|
||||
if launch_info and options.breakpoints:
|
||||
for bp in options.breakpoints:
|
||||
debugger.HandleCommand( "_regexp-break %s" % (bp))
|
||||
debugger.HandleCommand("_regexp-break %s" % (bp))
|
||||
run_commands(command_interpreter, ['breakpoint list'])
|
||||
|
||||
|
||||
for run_idx in range(options.run_count):
|
||||
# Launch the process. Since we specified synchronous mode, we won't return
|
||||
# from this function until we hit the breakpoint at main
|
||||
error = lldb.SBError()
|
||||
|
||||
|
||||
if launch_info:
|
||||
if options.run_count == 1:
|
||||
print 'Launching "%s"...' % (exe)
|
||||
else:
|
||||
print 'Launching "%s"... (launch %u of %u)' % (exe, run_idx + 1, options.run_count)
|
||||
|
||||
process = target.Launch (launch_info, error)
|
||||
|
||||
process = target.Launch(launch_info, error)
|
||||
else:
|
||||
if options.attach_pid != -1:
|
||||
print 'Attaching to process %i...' % (options.attach_pid)
|
||||
@@ -167,15 +296,16 @@ def main(argv):
|
||||
print 'Waiting for next to process named "%s" to launch...' % (options.attach_name)
|
||||
else:
|
||||
print 'Attaching to existing process named "%s"...' % (options.attach_name)
|
||||
process = target.Attach (attach_info, error)
|
||||
|
||||
process = target.Attach(attach_info, error)
|
||||
|
||||
# Make sure the launch went ok
|
||||
if process and process.GetProcessID() != lldb.LLDB_INVALID_PROCESS_ID:
|
||||
|
||||
|
||||
pid = process.GetProcessID()
|
||||
print 'Process is %i' % (pid)
|
||||
if attach_info:
|
||||
# continue process if we attached as we won't get an initial event
|
||||
# continue process if we attached as we won't get an
|
||||
# initial event
|
||||
process.Continue()
|
||||
|
||||
listener = debugger.GetListener()
|
||||
@@ -184,9 +314,9 @@ def main(argv):
|
||||
done = False
|
||||
while not done:
|
||||
event = lldb.SBEvent()
|
||||
if listener.WaitForEvent (options.event_timeout, event):
|
||||
if listener.WaitForEvent(options.event_timeout, event):
|
||||
if lldb.SBProcess.EventIsProcessEvent(event):
|
||||
state = lldb.SBProcess.GetStateFromEvent (event)
|
||||
state = lldb.SBProcess.GetStateFromEvent(event)
|
||||
if state == lldb.eStateInvalid:
|
||||
# Not a state event
|
||||
print 'process event = %s' % (event)
|
||||
@@ -196,42 +326,51 @@ def main(argv):
|
||||
if stop_idx == 0:
|
||||
if launch_info:
|
||||
print "process %u launched" % (pid)
|
||||
run_commands(command_interpreter, ['breakpoint list'])
|
||||
run_commands(
|
||||
command_interpreter, ['breakpoint list'])
|
||||
else:
|
||||
print "attached to process %u" % (pid)
|
||||
for m in target.modules:
|
||||
print m
|
||||
if options.breakpoints:
|
||||
for bp in options.breakpoints:
|
||||
debugger.HandleCommand( "_regexp-break %s" % (bp))
|
||||
run_commands(command_interpreter, ['breakpoint list'])
|
||||
run_commands (command_interpreter, options.launch_commands)
|
||||
debugger.HandleCommand(
|
||||
"_regexp-break %s" % (bp))
|
||||
run_commands(
|
||||
command_interpreter, ['breakpoint list'])
|
||||
run_commands(
|
||||
command_interpreter, options.launch_commands)
|
||||
else:
|
||||
if options.verbose:
|
||||
print "process %u stopped" % (pid)
|
||||
run_commands (command_interpreter, options.stop_commands)
|
||||
run_commands(
|
||||
command_interpreter, options.stop_commands)
|
||||
stop_idx += 1
|
||||
print_threads (process, options)
|
||||
print_threads(process, options)
|
||||
print "continuing process %u" % (pid)
|
||||
process.Continue()
|
||||
elif state == lldb.eStateExited:
|
||||
exit_desc = process.GetExitDescription()
|
||||
if exit_desc:
|
||||
print "process %u exited with status %u: %s" % (pid, process.GetExitStatus (), exit_desc)
|
||||
print "process %u exited with status %u: %s" % (pid, process.GetExitStatus(), exit_desc)
|
||||
else:
|
||||
print "process %u exited with status %u" % (pid, process.GetExitStatus ())
|
||||
run_commands (command_interpreter, options.exit_commands)
|
||||
print "process %u exited with status %u" % (pid, process.GetExitStatus())
|
||||
run_commands(
|
||||
command_interpreter, options.exit_commands)
|
||||
done = True
|
||||
elif state == lldb.eStateCrashed:
|
||||
print "process %u crashed" % (pid)
|
||||
print_threads (process, options)
|
||||
run_commands (command_interpreter, options.crash_commands)
|
||||
print_threads(process, options)
|
||||
run_commands(
|
||||
command_interpreter, options.crash_commands)
|
||||
done = True
|
||||
elif state == lldb.eStateDetached:
|
||||
print "process %u detached" % (pid)
|
||||
done = True
|
||||
elif state == lldb.eStateRunning:
|
||||
# process is running, don't say anything, we will always get one of these after resuming
|
||||
# process is running, don't say anything,
|
||||
# we will always get one of these after
|
||||
# resuming
|
||||
if options.verbose:
|
||||
print "process %u resumed" % (pid)
|
||||
elif state == lldb.eStateUnloaded:
|
||||
@@ -262,7 +401,7 @@ def main(argv):
|
||||
while process_stderr:
|
||||
process_stderr = process.GetSTDERR(1024)
|
||||
print process_stderr
|
||||
process.Kill() # kill the process
|
||||
process.Kill() # kill the process
|
||||
else:
|
||||
if error:
|
||||
print error
|
||||
@@ -271,8 +410,8 @@ def main(argv):
|
||||
print 'error: launch failed'
|
||||
else:
|
||||
print 'error: attach failed'
|
||||
|
||||
|
||||
lldb.SBDebugger.Terminate()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(sys.argv[1:])
|
||||
main(sys.argv[1:])
|
||||
|
||||
@@ -2,310 +2,342 @@ import sys
|
||||
import inspect
|
||||
from collections import OrderedDict
|
||||
|
||||
|
||||
class TracebackFancy:
|
||||
def __init__(self,traceback):
|
||||
self.t = traceback
|
||||
|
||||
def getFrame(self):
|
||||
return FrameFancy(self.t.tb_frame)
|
||||
def __init__(self, traceback):
|
||||
self.t = traceback
|
||||
|
||||
def getLineNumber(self):
|
||||
return self.t.tb_lineno if self.t != None else None
|
||||
def getFrame(self):
|
||||
return FrameFancy(self.t.tb_frame)
|
||||
|
||||
def getNext(self):
|
||||
return TracebackFancy(self.t.tb_next)
|
||||
def getLineNumber(self):
|
||||
return self.t.tb_lineno if self.t is not None else None
|
||||
|
||||
def getNext(self):
|
||||
return TracebackFancy(self.t.tb_next)
|
||||
|
||||
def __str__(self):
|
||||
if self.t is None:
|
||||
return ""
|
||||
str_self = "%s @ %s" % (
|
||||
self.getFrame().getName(), self.getLineNumber())
|
||||
return str_self + "\n" + self.getNext().__str__()
|
||||
|
||||
def __str__(self):
|
||||
if self.t == None:
|
||||
return ""
|
||||
str_self = "%s @ %s" % (self.getFrame().getName(), self.getLineNumber())
|
||||
return str_self + "\n" + self.getNext().__str__()
|
||||
|
||||
class ExceptionFancy:
|
||||
def __init__(self,frame):
|
||||
self.etraceback = frame.f_exc_traceback
|
||||
self.etype = frame.exc_type
|
||||
self.evalue = frame.f_exc_value
|
||||
|
||||
def __init__(self,tb,ty,va):
|
||||
self.etraceback = tb
|
||||
self.etype = ty
|
||||
self.evalue = va
|
||||
def __init__(self, frame):
|
||||
self.etraceback = frame.f_exc_traceback
|
||||
self.etype = frame.exc_type
|
||||
self.evalue = frame.f_exc_value
|
||||
|
||||
def getTraceback(self):
|
||||
return TracebackFancy(self.etraceback)
|
||||
def __init__(self, tb, ty, va):
|
||||
self.etraceback = tb
|
||||
self.etype = ty
|
||||
self.evalue = va
|
||||
|
||||
def __nonzero__(self):
|
||||
return self.etraceback != None or self.etype != None or self.evalue != None
|
||||
def getTraceback(self):
|
||||
return TracebackFancy(self.etraceback)
|
||||
|
||||
def getType(self):
|
||||
return str(self.etype)
|
||||
def __nonzero__(self):
|
||||
return self.etraceback is not None or self.etype is not None or self.evalue is not None
|
||||
|
||||
def getType(self):
|
||||
return str(self.etype)
|
||||
|
||||
def getValue(self):
|
||||
return self.evalue
|
||||
|
||||
def getValue(self):
|
||||
return self.evalue
|
||||
|
||||
class CodeFancy:
|
||||
def __init__(self,code):
|
||||
self.c = code
|
||||
|
||||
def getArgCount(self):
|
||||
return self.c.co_argcount if self.c != None else 0
|
||||
def __init__(self, code):
|
||||
self.c = code
|
||||
|
||||
def getFilename(self):
|
||||
return self.c.co_filename if self.c != None else ""
|
||||
def getArgCount(self):
|
||||
return self.c.co_argcount if self.c is not None else 0
|
||||
|
||||
def getVariables(self):
|
||||
return self.c.co_varnames if self.c != None else []
|
||||
def getFilename(self):
|
||||
return self.c.co_filename if self.c is not None else ""
|
||||
|
||||
def getName(self):
|
||||
return self.c.co_name if self.c != None else ""
|
||||
def getVariables(self):
|
||||
return self.c.co_varnames if self.c is not None else []
|
||||
|
||||
def getName(self):
|
||||
return self.c.co_name if self.c is not None else ""
|
||||
|
||||
def getFileName(self):
|
||||
return self.c.co_filename if self.c is not None else ""
|
||||
|
||||
def getFileName(self):
|
||||
return self.c.co_filename if self.c != None else ""
|
||||
|
||||
class ArgsFancy:
|
||||
def __init__(self,frame,arginfo):
|
||||
self.f = frame
|
||||
self.a = arginfo
|
||||
|
||||
def __str__(self):
|
||||
args, varargs, kwargs = self.getArgs(), self.getVarArgs(), self.getKWArgs()
|
||||
ret = ""
|
||||
count = 0
|
||||
size = len(args)
|
||||
for arg in args:
|
||||
ret = ret + ("%s = %s" % (arg, args[arg]))
|
||||
count = count + 1
|
||||
if count < size:
|
||||
ret = ret + ", "
|
||||
if varargs:
|
||||
if size > 0:
|
||||
ret = ret + " "
|
||||
ret = ret + "varargs are " + str(varargs)
|
||||
if kwargs:
|
||||
if size > 0:
|
||||
ret = ret + " "
|
||||
ret = ret + "kwargs are " + str(kwargs)
|
||||
return ret
|
||||
def __init__(self, frame, arginfo):
|
||||
self.f = frame
|
||||
self.a = arginfo
|
||||
|
||||
def getNumArgs(wantVarargs = False, wantKWArgs=False):
|
||||
args, varargs, keywords, values = self.a
|
||||
size = len(args)
|
||||
if varargs and wantVarargs:
|
||||
size = size+len(self.getVarArgs())
|
||||
if keywords and wantKWArgs:
|
||||
size = size+len(self.getKWArgs())
|
||||
return size
|
||||
def __str__(self):
|
||||
args, varargs, kwargs = self.getArgs(), self.getVarArgs(), self.getKWArgs()
|
||||
ret = ""
|
||||
count = 0
|
||||
size = len(args)
|
||||
for arg in args:
|
||||
ret = ret + ("%s = %s" % (arg, args[arg]))
|
||||
count = count + 1
|
||||
if count < size:
|
||||
ret = ret + ", "
|
||||
if varargs:
|
||||
if size > 0:
|
||||
ret = ret + " "
|
||||
ret = ret + "varargs are " + str(varargs)
|
||||
if kwargs:
|
||||
if size > 0:
|
||||
ret = ret + " "
|
||||
ret = ret + "kwargs are " + str(kwargs)
|
||||
return ret
|
||||
|
||||
def getArgs(self):
|
||||
args, _, _, values = self.a
|
||||
argWValues = OrderedDict()
|
||||
for arg in args:
|
||||
argWValues[arg] = values[arg]
|
||||
return argWValues
|
||||
def getNumArgs(wantVarargs=False, wantKWArgs=False):
|
||||
args, varargs, keywords, values = self.a
|
||||
size = len(args)
|
||||
if varargs and wantVarargs:
|
||||
size = size + len(self.getVarArgs())
|
||||
if keywords and wantKWArgs:
|
||||
size = size + len(self.getKWArgs())
|
||||
return size
|
||||
|
||||
def getVarArgs(self):
|
||||
_, vargs, _, _ = self.a
|
||||
if vargs:
|
||||
return self.f.f_locals[vargs]
|
||||
return ()
|
||||
def getArgs(self):
|
||||
args, _, _, values = self.a
|
||||
argWValues = OrderedDict()
|
||||
for arg in args:
|
||||
argWValues[arg] = values[arg]
|
||||
return argWValues
|
||||
|
||||
def getVarArgs(self):
|
||||
_, vargs, _, _ = self.a
|
||||
if vargs:
|
||||
return self.f.f_locals[vargs]
|
||||
return ()
|
||||
|
||||
def getKWArgs(self):
|
||||
_, _, kwargs, _ = self.a
|
||||
if kwargs:
|
||||
return self.f.f_locals[kwargs]
|
||||
return {}
|
||||
|
||||
def getKWArgs(self):
|
||||
_, _, kwargs, _ = self.a
|
||||
if kwargs:
|
||||
return self.f.f_locals[kwargs]
|
||||
return {}
|
||||
|
||||
class FrameFancy:
|
||||
def __init__(self,frame):
|
||||
self.f = frame
|
||||
|
||||
def getCaller(self):
|
||||
return FrameFancy(self.f.f_back)
|
||||
def __init__(self, frame):
|
||||
self.f = frame
|
||||
|
||||
def getLineNumber(self):
|
||||
return self.f.f_lineno if self.f != None else 0
|
||||
def getCaller(self):
|
||||
return FrameFancy(self.f.f_back)
|
||||
|
||||
def getCodeInformation(self):
|
||||
return CodeFancy(self.f.f_code) if self.f != None else None
|
||||
def getLineNumber(self):
|
||||
return self.f.f_lineno if self.f is not None else 0
|
||||
|
||||
def getExceptionInfo(self):
|
||||
return ExceptionFancy(self.f) if self.f != None else None
|
||||
def getCodeInformation(self):
|
||||
return CodeFancy(self.f.f_code) if self.f is not None else None
|
||||
|
||||
def getName(self):
|
||||
return self.getCodeInformation().getName() if self.f != None else ""
|
||||
def getExceptionInfo(self):
|
||||
return ExceptionFancy(self.f) if self.f is not None else None
|
||||
|
||||
def getFileName(self):
|
||||
return self.getCodeInformation().getFileName() if self.f != None else ""
|
||||
def getName(self):
|
||||
return self.getCodeInformation().getName() if self.f is not None else ""
|
||||
|
||||
def getFileName(self):
|
||||
return self.getCodeInformation().getFileName() if self.f is not None else ""
|
||||
|
||||
def getLocals(self):
|
||||
return self.f.f_locals if self.f is not None else {}
|
||||
|
||||
def getArgumentInfo(self):
|
||||
return ArgsFancy(
|
||||
self.f, inspect.getargvalues(
|
||||
self.f)) if self.f is not None else None
|
||||
|
||||
def getLocals(self):
|
||||
return self.f.f_locals if self.f != None else {}
|
||||
|
||||
def getArgumentInfo(self):
|
||||
return ArgsFancy(self.f,inspect.getargvalues(self.f)) if self.f != None else None
|
||||
|
||||
class TracerClass:
|
||||
def callEvent(self,frame):
|
||||
pass
|
||||
|
||||
def lineEvent(self,frame):
|
||||
pass
|
||||
def callEvent(self, frame):
|
||||
pass
|
||||
|
||||
def returnEvent(self,frame,retval):
|
||||
pass
|
||||
def lineEvent(self, frame):
|
||||
pass
|
||||
|
||||
def exceptionEvent(self,frame,exception,value,traceback):
|
||||
pass
|
||||
def returnEvent(self, frame, retval):
|
||||
pass
|
||||
|
||||
def cCallEvent(self,frame,cfunct):
|
||||
pass
|
||||
def exceptionEvent(self, frame, exception, value, traceback):
|
||||
pass
|
||||
|
||||
def cReturnEvent(self,frame,cfunct):
|
||||
pass
|
||||
def cCallEvent(self, frame, cfunct):
|
||||
pass
|
||||
|
||||
def cExceptionEvent(self,frame,cfunct):
|
||||
pass
|
||||
def cReturnEvent(self, frame, cfunct):
|
||||
pass
|
||||
|
||||
def cExceptionEvent(self, frame, cfunct):
|
||||
pass
|
||||
|
||||
tracer_impl = TracerClass()
|
||||
|
||||
|
||||
def the_tracer_entrypoint(frame,event,args):
|
||||
if tracer_impl == None:
|
||||
return None
|
||||
if event == "call":
|
||||
call_retval = tracer_impl.callEvent(FrameFancy(frame))
|
||||
if call_retval == False:
|
||||
return None
|
||||
return the_tracer_entrypoint
|
||||
elif event == "line":
|
||||
line_retval = tracer_impl.lineEvent(FrameFancy(frame))
|
||||
if line_retval == False:
|
||||
return None
|
||||
return the_tracer_entrypoint
|
||||
elif event == "return":
|
||||
tracer_impl.returnEvent(FrameFancy(frame),args)
|
||||
elif event == "exception":
|
||||
exty,exva,extb = args
|
||||
exception_retval = tracer_impl.exceptionEvent(FrameFancy(frame),ExceptionFancy(extb,exty,exva))
|
||||
if exception_retval == False:
|
||||
return None
|
||||
return the_tracer_entrypoint
|
||||
elif event == "c_call":
|
||||
tracer_impl.cCallEvent(FrameFancy(frame),args)
|
||||
elif event == "c_return":
|
||||
tracer_impl.cReturnEvent(FrameFancy(frame),args)
|
||||
elif event == "c_exception":
|
||||
tracer_impl.cExceptionEvent(FrameFancy(frame),args)
|
||||
return None
|
||||
def the_tracer_entrypoint(frame, event, args):
|
||||
if tracer_impl is None:
|
||||
return None
|
||||
if event == "call":
|
||||
call_retval = tracer_impl.callEvent(FrameFancy(frame))
|
||||
if not call_retval:
|
||||
return None
|
||||
return the_tracer_entrypoint
|
||||
elif event == "line":
|
||||
line_retval = tracer_impl.lineEvent(FrameFancy(frame))
|
||||
if not line_retval:
|
||||
return None
|
||||
return the_tracer_entrypoint
|
||||
elif event == "return":
|
||||
tracer_impl.returnEvent(FrameFancy(frame), args)
|
||||
elif event == "exception":
|
||||
exty, exva, extb = args
|
||||
exception_retval = tracer_impl.exceptionEvent(
|
||||
FrameFancy(frame), ExceptionFancy(extb, exty, exva))
|
||||
if not exception_retval:
|
||||
return None
|
||||
return the_tracer_entrypoint
|
||||
elif event == "c_call":
|
||||
tracer_impl.cCallEvent(FrameFancy(frame), args)
|
||||
elif event == "c_return":
|
||||
tracer_impl.cReturnEvent(FrameFancy(frame), args)
|
||||
elif event == "c_exception":
|
||||
tracer_impl.cExceptionEvent(FrameFancy(frame), args)
|
||||
return None
|
||||
|
||||
|
||||
def enable(t=None):
|
||||
global tracer_impl
|
||||
if t:
|
||||
tracer_impl = t
|
||||
sys.settrace(the_tracer_entrypoint)
|
||||
global tracer_impl
|
||||
if t:
|
||||
tracer_impl = t
|
||||
sys.settrace(the_tracer_entrypoint)
|
||||
|
||||
|
||||
def disable():
|
||||
sys.settrace(None)
|
||||
sys.settrace(None)
|
||||
|
||||
|
||||
class LoggingTracer:
|
||||
def callEvent(self,frame):
|
||||
print "call " + frame.getName() + " from " + frame.getCaller().getName() + " @ " + str(frame.getCaller().getLineNumber()) + " args are " + str(frame.getArgumentInfo())
|
||||
|
||||
def lineEvent(self,frame):
|
||||
print "running " + frame.getName() + " @ " + str(frame.getLineNumber()) + " locals are " + str(frame.getLocals()) + " in " + frame.getFileName()
|
||||
def callEvent(self, frame):
|
||||
print "call " + frame.getName() + " from " + frame.getCaller().getName() + " @ " + str(frame.getCaller().getLineNumber()) + " args are " + str(frame.getArgumentInfo())
|
||||
|
||||
def returnEvent(self,frame,retval):
|
||||
print "return from " + frame.getName() + " value is " + str(retval) + " locals are " + str(frame.getLocals())
|
||||
def lineEvent(self, frame):
|
||||
print "running " + frame.getName() + " @ " + str(frame.getLineNumber()) + " locals are " + str(frame.getLocals()) + " in " + frame.getFileName()
|
||||
|
||||
def returnEvent(self, frame, retval):
|
||||
print "return from " + frame.getName() + " value is " + str(retval) + " locals are " + str(frame.getLocals())
|
||||
|
||||
def exceptionEvent(self, frame, exception):
|
||||
print "exception %s %s raised from %s @ %s" % (exception.getType(), str(exception.getValue()), frame.getName(), frame.getLineNumber())
|
||||
print "tb: " + str(exception.getTraceback())
|
||||
|
||||
# the same functionality as LoggingTracer, but with a little more
|
||||
# lldb-specific smarts
|
||||
|
||||
def exceptionEvent(self,frame,exception):
|
||||
print "exception %s %s raised from %s @ %s" % (exception.getType(), str(exception.getValue()), frame.getName(), frame.getLineNumber())
|
||||
print "tb: " + str(exception.getTraceback())
|
||||
|
||||
# the same functionality as LoggingTracer, but with a little more lldb-specific smarts
|
||||
class LLDBAwareTracer:
|
||||
def callEvent(self,frame):
|
||||
if frame.getName() == "<module>":
|
||||
return
|
||||
if frame.getName() == "run_one_line":
|
||||
print "call run_one_line(%s)" % (frame.getArgumentInfo().getArgs()["input_string"])
|
||||
return
|
||||
if "Python.framework" in frame.getFileName():
|
||||
print "call into Python at " + frame.getName()
|
||||
return
|
||||
if frame.getName() == "__init__" and frame.getCaller().getName() == "run_one_line" and frame.getCaller().getLineNumber() == 101:
|
||||
return False
|
||||
strout = "call " + frame.getName()
|
||||
if (frame.getCaller().getFileName() == ""):
|
||||
strout += " from LLDB - args are "
|
||||
args = frame.getArgumentInfo().getArgs()
|
||||
for arg in args:
|
||||
if arg == "dict" or arg == "internal_dict":
|
||||
continue
|
||||
strout = strout + ("%s = %s " % (arg,args[arg]))
|
||||
else:
|
||||
strout += " from " + frame.getCaller().getName() + " @ " + str(frame.getCaller().getLineNumber()) + " args are " + str(frame.getArgumentInfo())
|
||||
print strout
|
||||
|
||||
def lineEvent(self,frame):
|
||||
if frame.getName() == "<module>":
|
||||
return
|
||||
if frame.getName() == "run_one_line":
|
||||
print "running run_one_line(%s) @ %s" % (frame.getArgumentInfo().getArgs()["input_string"],frame.getLineNumber())
|
||||
return
|
||||
if "Python.framework" in frame.getFileName():
|
||||
print "running into Python at " + frame.getName() + " @ " + str(frame.getLineNumber())
|
||||
return
|
||||
strout = "running " + frame.getName() + " @ " + str(frame.getLineNumber()) + " locals are "
|
||||
if (frame.getCaller().getFileName() == ""):
|
||||
locals = frame.getLocals()
|
||||
for local in locals:
|
||||
if local == "dict" or local == "internal_dict":
|
||||
continue
|
||||
strout = strout + ("%s = %s " % (local,locals[local]))
|
||||
else:
|
||||
strout = strout + str(frame.getLocals())
|
||||
strout = strout + " in " + frame.getFileName()
|
||||
print strout
|
||||
def callEvent(self, frame):
|
||||
if frame.getName() == "<module>":
|
||||
return
|
||||
if frame.getName() == "run_one_line":
|
||||
print "call run_one_line(%s)" % (frame.getArgumentInfo().getArgs()["input_string"])
|
||||
return
|
||||
if "Python.framework" in frame.getFileName():
|
||||
print "call into Python at " + frame.getName()
|
||||
return
|
||||
if frame.getName() == "__init__" and frame.getCaller().getName(
|
||||
) == "run_one_line" and frame.getCaller().getLineNumber() == 101:
|
||||
return False
|
||||
strout = "call " + frame.getName()
|
||||
if (frame.getCaller().getFileName() == ""):
|
||||
strout += " from LLDB - args are "
|
||||
args = frame.getArgumentInfo().getArgs()
|
||||
for arg in args:
|
||||
if arg == "dict" or arg == "internal_dict":
|
||||
continue
|
||||
strout = strout + ("%s = %s " % (arg, args[arg]))
|
||||
else:
|
||||
strout += " from " + frame.getCaller().getName() + " @ " + \
|
||||
str(frame.getCaller().getLineNumber()) + " args are " + str(frame.getArgumentInfo())
|
||||
print strout
|
||||
|
||||
def returnEvent(self,frame,retval):
|
||||
if frame.getName() == "<module>":
|
||||
return
|
||||
if frame.getName() == "run_one_line":
|
||||
print "return from run_one_line(%s) return value is %s" % (frame.getArgumentInfo().getArgs()["input_string"],retval)
|
||||
return
|
||||
if "Python.framework" in frame.getFileName():
|
||||
print "return from Python at " + frame.getName() + " return value is " + str(retval)
|
||||
return
|
||||
strout = "return from " + frame.getName() + " return value is " + str(retval) + " locals are "
|
||||
if (frame.getCaller().getFileName() == ""):
|
||||
locals = frame.getLocals()
|
||||
for local in locals:
|
||||
if local == "dict" or local == "internal_dict":
|
||||
continue
|
||||
strout = strout + ("%s = %s " % (local,locals[local]))
|
||||
else:
|
||||
strout = strout + str(frame.getLocals())
|
||||
strout = strout + " in " + frame.getFileName()
|
||||
print strout
|
||||
def lineEvent(self, frame):
|
||||
if frame.getName() == "<module>":
|
||||
return
|
||||
if frame.getName() == "run_one_line":
|
||||
print "running run_one_line(%s) @ %s" % (frame.getArgumentInfo().getArgs()["input_string"], frame.getLineNumber())
|
||||
return
|
||||
if "Python.framework" in frame.getFileName():
|
||||
print "running into Python at " + frame.getName() + " @ " + str(frame.getLineNumber())
|
||||
return
|
||||
strout = "running " + frame.getName() + " @ " + str(frame.getLineNumber()) + \
|
||||
" locals are "
|
||||
if (frame.getCaller().getFileName() == ""):
|
||||
locals = frame.getLocals()
|
||||
for local in locals:
|
||||
if local == "dict" or local == "internal_dict":
|
||||
continue
|
||||
strout = strout + ("%s = %s " % (local, locals[local]))
|
||||
else:
|
||||
strout = strout + str(frame.getLocals())
|
||||
strout = strout + " in " + frame.getFileName()
|
||||
print strout
|
||||
|
||||
def exceptionEvent(self,frame,exception):
|
||||
if frame.getName() == "<module>":
|
||||
return
|
||||
print "exception %s %s raised from %s @ %s" % (exception.getType(), str(exception.getValue()), frame.getName(), frame.getLineNumber())
|
||||
print "tb: " + str(exception.getTraceback())
|
||||
def returnEvent(self, frame, retval):
|
||||
if frame.getName() == "<module>":
|
||||
return
|
||||
if frame.getName() == "run_one_line":
|
||||
print "return from run_one_line(%s) return value is %s" % (frame.getArgumentInfo().getArgs()["input_string"], retval)
|
||||
return
|
||||
if "Python.framework" in frame.getFileName():
|
||||
print "return from Python at " + frame.getName() + " return value is " + str(retval)
|
||||
return
|
||||
strout = "return from " + frame.getName() + " return value is " + \
|
||||
str(retval) + " locals are "
|
||||
if (frame.getCaller().getFileName() == ""):
|
||||
locals = frame.getLocals()
|
||||
for local in locals:
|
||||
if local == "dict" or local == "internal_dict":
|
||||
continue
|
||||
strout = strout + ("%s = %s " % (local, locals[local]))
|
||||
else:
|
||||
strout = strout + str(frame.getLocals())
|
||||
strout = strout + " in " + frame.getFileName()
|
||||
print strout
|
||||
|
||||
def exceptionEvent(self, frame, exception):
|
||||
if frame.getName() == "<module>":
|
||||
return
|
||||
print "exception %s %s raised from %s @ %s" % (exception.getType(), str(exception.getValue()), frame.getName(), frame.getLineNumber())
|
||||
print "tb: " + str(exception.getTraceback())
|
||||
|
||||
|
||||
def f(x, y=None):
|
||||
if x > 0:
|
||||
return 2 + f(x - 2)
|
||||
return 35
|
||||
|
||||
def f(x,y=None):
|
||||
if x > 0:
|
||||
return 2 + f(x-2)
|
||||
return 35
|
||||
|
||||
def g(x):
|
||||
return 1.134 / x
|
||||
return 1.134 / x
|
||||
|
||||
|
||||
def print_keyword_args(**kwargs):
|
||||
# kwargs is a dict of the keyword args passed to the function
|
||||
for key, value in kwargs.iteritems():
|
||||
print "%s = %s" % (key, value)
|
||||
# kwargs is a dict of the keyword args passed to the function
|
||||
for key, value in kwargs.iteritems():
|
||||
print "%s = %s" % (key, value)
|
||||
|
||||
|
||||
def total(initial=5, *numbers, **keywords):
|
||||
count = initial
|
||||
@@ -316,13 +348,13 @@ def total(initial=5, *numbers, **keywords):
|
||||
return count
|
||||
|
||||
if __name__ == "__main__":
|
||||
enable(LoggingTracer())
|
||||
f(5)
|
||||
f(5,1)
|
||||
print_keyword_args(first_name="John", last_name="Doe")
|
||||
total(10, 1, 2, 3, vegetables=50, fruits=100)
|
||||
try:
|
||||
g(0)
|
||||
except:
|
||||
pass
|
||||
disable()
|
||||
enable(LoggingTracer())
|
||||
f(5)
|
||||
f(5, 1)
|
||||
print_keyword_args(first_name="John", last_name="Doe")
|
||||
total(10, 1, 2, 3, vegetables=50, fruits=100)
|
||||
try:
|
||||
g(0)
|
||||
except:
|
||||
pass
|
||||
disable()
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import lldb
|
||||
|
||||
|
||||
class value(object):
|
||||
'''A class that wraps an lldb.SBValue object and returns an object that
|
||||
can be used as an object with attribytes:\n
|
||||
@@ -24,6 +25,7 @@ class value(object):
|
||||
argv.num_children - return the number of children this value has
|
||||
argv.children - return a list of sbvalue objects that represents all of the children of this value
|
||||
'''
|
||||
|
||||
def __init__(self, sbvalue):
|
||||
self.sbvalue = sbvalue
|
||||
|
||||
@@ -37,10 +39,12 @@ class value(object):
|
||||
return self.sbvalue.__str__()
|
||||
|
||||
def __getitem__(self, key):
|
||||
if type(key) is int:
|
||||
return value(self.sbvalue.GetChildAtIndex(key, lldb.eNoDynamicValues, True))
|
||||
if isinstance(key, int):
|
||||
return value(
|
||||
self.sbvalue.GetChildAtIndex(
|
||||
key, lldb.eNoDynamicValues, True))
|
||||
raise TypeError
|
||||
|
||||
|
||||
def __getattr__(self, name):
|
||||
if name == 'name':
|
||||
return self.sbvalue.GetName()
|
||||
@@ -55,15 +59,15 @@ class value(object):
|
||||
if name == 'is_pointer':
|
||||
return self.sbvalue.TypeIsPointerType()
|
||||
if name == 'format':
|
||||
return self.sbvalue.GetFormat ()
|
||||
return self.sbvalue.GetFormat()
|
||||
if name == 'value':
|
||||
return self.sbvalue.GetValue ()
|
||||
return self.sbvalue.GetValue()
|
||||
if name == 'summary':
|
||||
return self.sbvalue.GetSummary ()
|
||||
return self.sbvalue.GetSummary()
|
||||
if name == 'description':
|
||||
return self.sbvalue.GetObjectDescription ()
|
||||
return self.sbvalue.GetObjectDescription()
|
||||
if name == 'location':
|
||||
return self.sbvalue.GetLocation ()
|
||||
return self.sbvalue.GetLocation()
|
||||
if name == 'target':
|
||||
return self.sbvalue.GetTarget()
|
||||
if name == 'process':
|
||||
@@ -75,18 +79,25 @@ class value(object):
|
||||
if name == 'num_children':
|
||||
return self.sbvalue.GetNumChildren()
|
||||
if name == 'children':
|
||||
# Returns an array of sbvalue objects, one for each child of
|
||||
# Returns an array of sbvalue objects, one for each child of
|
||||
# the value for the lldb.SBValue
|
||||
children = []
|
||||
for i in range (self.sbvalue.GetNumChildren()):
|
||||
children.append(value(self.sbvalue.GetChildAtIndex(i, lldb.eNoDynamicValues, True)))
|
||||
for i in range(self.sbvalue.GetNumChildren()):
|
||||
children.append(
|
||||
value(
|
||||
self.sbvalue.GetChildAtIndex(
|
||||
i,
|
||||
lldb.eNoDynamicValues,
|
||||
True)))
|
||||
return children
|
||||
raise AttributeError
|
||||
|
||||
|
||||
|
||||
class variable(object):
|
||||
'''A class that treats a lldb.SBValue and allows it to be used just as
|
||||
a variable would be in code. So if you have a Point structure variable
|
||||
a variable would be in code. So if you have a Point structure variable
|
||||
in your code, you would be able to do: "pt.x + pt.y"'''
|
||||
|
||||
def __init__(self, sbvalue):
|
||||
self.sbvalue = sbvalue
|
||||
|
||||
@@ -101,155 +112,157 @@ class variable(object):
|
||||
|
||||
def __getitem__(self, key):
|
||||
# Allow array access if this value has children...
|
||||
if type(key) is int:
|
||||
return variable(self.sbvalue.GetValueForExpressionPath("[%i]" % key))
|
||||
if isinstance(key, int):
|
||||
return variable(
|
||||
self.sbvalue.GetValueForExpressionPath(
|
||||
"[%i]" %
|
||||
key))
|
||||
raise TypeError
|
||||
|
||||
def __getattr__(self, name):
|
||||
child_sbvalue = self.sbvalue.GetChildMemberWithName (name)
|
||||
child_sbvalue = self.sbvalue.GetChildMemberWithName(name)
|
||||
if child_sbvalue:
|
||||
return variable(child_sbvalue)
|
||||
raise AttributeError
|
||||
|
||||
def __add__(self, other):
|
||||
return int(self) + int(other)
|
||||
|
||||
|
||||
def __sub__(self, other):
|
||||
return int(self) - int(other)
|
||||
|
||||
|
||||
def __mul__(self, other):
|
||||
return int(self) * int(other)
|
||||
|
||||
|
||||
def __floordiv__(self, other):
|
||||
return int(self) // int(other)
|
||||
|
||||
|
||||
def __mod__(self, other):
|
||||
return int(self) % int(other)
|
||||
|
||||
|
||||
def __divmod__(self, other):
|
||||
return int(self) % int(other)
|
||||
|
||||
|
||||
def __pow__(self, other):
|
||||
return int(self) ** int(other)
|
||||
|
||||
|
||||
def __lshift__(self, other):
|
||||
return int(self) << int(other)
|
||||
|
||||
|
||||
def __rshift__(self, other):
|
||||
return int(self) >> int(other)
|
||||
|
||||
|
||||
def __and__(self, other):
|
||||
return int(self) & int(other)
|
||||
|
||||
|
||||
def __xor__(self, other):
|
||||
return int(self) ^ int(other)
|
||||
|
||||
|
||||
def __or__(self, other):
|
||||
return int(self) | int(other)
|
||||
|
||||
|
||||
def __div__(self, other):
|
||||
return int(self) / int(other)
|
||||
|
||||
|
||||
def __truediv__(self, other):
|
||||
return int(self) / int(other)
|
||||
|
||||
|
||||
def __iadd__(self, other):
|
||||
result = self.__add__(other)
|
||||
self.sbvalue.SetValueFromCString (str(result))
|
||||
self.sbvalue.SetValueFromCString(str(result))
|
||||
return result
|
||||
|
||||
|
||||
def __isub__(self, other):
|
||||
result = self.__sub__(other)
|
||||
self.sbvalue.SetValueFromCString (str(result))
|
||||
self.sbvalue.SetValueFromCString(str(result))
|
||||
return result
|
||||
|
||||
|
||||
def __imul__(self, other):
|
||||
result = self.__mul__(other)
|
||||
self.sbvalue.SetValueFromCString (str(result))
|
||||
self.sbvalue.SetValueFromCString(str(result))
|
||||
return result
|
||||
|
||||
|
||||
def __idiv__(self, other):
|
||||
result = self.__div__(other)
|
||||
self.sbvalue.SetValueFromCString (str(result))
|
||||
self.sbvalue.SetValueFromCString(str(result))
|
||||
return result
|
||||
|
||||
|
||||
def __itruediv__(self, other):
|
||||
result = self.__truediv__(other)
|
||||
self.sbvalue.SetValueFromCString (str(result))
|
||||
self.sbvalue.SetValueFromCString(str(result))
|
||||
return result
|
||||
|
||||
|
||||
def __ifloordiv__(self, other):
|
||||
result = self.__floordiv__(self, other)
|
||||
self.sbvalue.SetValueFromCString (str(result))
|
||||
result = self.__floordiv__(self, other)
|
||||
self.sbvalue.SetValueFromCString(str(result))
|
||||
return result
|
||||
|
||||
|
||||
def __imod__(self, other):
|
||||
result = self.__and__(self, other)
|
||||
self.sbvalue.SetValueFromCString (str(result))
|
||||
result = self.__and__(self, other)
|
||||
self.sbvalue.SetValueFromCString(str(result))
|
||||
return result
|
||||
|
||||
|
||||
def __ipow__(self, other):
|
||||
result = self.__pow__(self, other)
|
||||
self.sbvalue.SetValueFromCString (str(result))
|
||||
self.sbvalue.SetValueFromCString(str(result))
|
||||
return result
|
||||
|
||||
|
||||
def __ipow__(self, other, modulo):
|
||||
result = self.__pow__(self, other, modulo)
|
||||
self.sbvalue.SetValueFromCString (str(result))
|
||||
self.sbvalue.SetValueFromCString(str(result))
|
||||
return result
|
||||
|
||||
|
||||
def __ilshift__(self, other):
|
||||
result = self.__lshift__(self, other)
|
||||
self.sbvalue.SetValueFromCString (str(result))
|
||||
self.sbvalue.SetValueFromCString(str(result))
|
||||
return result
|
||||
|
||||
|
||||
def __irshift__(self, other):
|
||||
result = self.__rshift__(self, other)
|
||||
self.sbvalue.SetValueFromCString (str(result))
|
||||
result = self.__rshift__(self, other)
|
||||
self.sbvalue.SetValueFromCString(str(result))
|
||||
return result
|
||||
|
||||
|
||||
def __iand__(self, other):
|
||||
result = self.__and__(self, other)
|
||||
self.sbvalue.SetValueFromCString (str(result))
|
||||
result = self.__and__(self, other)
|
||||
self.sbvalue.SetValueFromCString(str(result))
|
||||
return result
|
||||
|
||||
|
||||
def __ixor__(self, other):
|
||||
result = self.__xor__(self, other)
|
||||
self.sbvalue.SetValueFromCString (str(result))
|
||||
result = self.__xor__(self, other)
|
||||
self.sbvalue.SetValueFromCString(str(result))
|
||||
return result
|
||||
|
||||
|
||||
def __ior__(self, other):
|
||||
result = self.__ior__(self, other)
|
||||
self.sbvalue.SetValueFromCString (str(result))
|
||||
result = self.__ior__(self, other)
|
||||
self.sbvalue.SetValueFromCString(str(result))
|
||||
return result
|
||||
|
||||
|
||||
def __neg__(self):
|
||||
return -int(self)
|
||||
|
||||
|
||||
def __pos__(self):
|
||||
return +int(self)
|
||||
|
||||
|
||||
def __abs__(self):
|
||||
return abs(int(self))
|
||||
|
||||
|
||||
def __invert__(self):
|
||||
return ~int(self)
|
||||
|
||||
|
||||
def __complex__(self):
|
||||
return complex (int(self))
|
||||
|
||||
return complex(int(self))
|
||||
|
||||
def __int__(self):
|
||||
return self.sbvalue.GetValueAsSigned()
|
||||
|
||||
|
||||
def __long__(self):
|
||||
return self.sbvalue.GetValueAsSigned()
|
||||
|
||||
|
||||
def __float__(self):
|
||||
return float (self.sbvalue.GetValueAsSigned())
|
||||
|
||||
return float(self.sbvalue.GetValueAsSigned())
|
||||
|
||||
def __oct__(self):
|
||||
return '0%o' % self.sbvalue.GetValueAsSigned()
|
||||
|
||||
|
||||
def __hex__(self):
|
||||
return '0x%x' % self.sbvalue.GetValueAsSigned()
|
||||
|
||||
@@ -5,15 +5,15 @@
|
||||
# interface is a reduced version of the full internal mechanism, but captures
|
||||
# most of the power with a much simpler interface.
|
||||
#
|
||||
# But I'll attempt a brief summary here.
|
||||
# But I'll attempt a brief summary here.
|
||||
# Stepping in lldb is done independently for each thread. Moreover, the stepping
|
||||
# operations are stackable. So for instance if you did a "step over", and in
|
||||
# operations are stackable. So for instance if you did a "step over", and in
|
||||
# the course of stepping over you hit a breakpoint, stopped and stepped again,
|
||||
# the first "step-over" would be suspended, and the new step operation would
|
||||
# be enqueued. Then if that step over caused the program to hit another breakpoint,
|
||||
# lldb would again suspend the second step and return control to the user, so
|
||||
# now there are two pending step overs. Etc. with all the other stepping
|
||||
# operations. Then if you hit "continue" the bottom-most step-over would complete,
|
||||
# now there are two pending step overs. Etc. with all the other stepping
|
||||
# operations. Then if you hit "continue" the bottom-most step-over would complete,
|
||||
# and another continue would complete the first "step-over".
|
||||
#
|
||||
# lldb represents this system with a stack of "Thread Plans". Each time a new
|
||||
@@ -26,16 +26,16 @@
|
||||
# the current thread. In the scripted interface, you indicate this by returning
|
||||
# False or True respectively from the should_step method.
|
||||
#
|
||||
# Each time the process stops the thread plan stack for each thread that stopped
|
||||
# Each time the process stops the thread plan stack for each thread that stopped
|
||||
# "for a reason", Ii.e. a single-step completed on that thread, or a breakpoint
|
||||
# was hit), is queried to determine how to proceed, starting from the most
|
||||
# was hit), is queried to determine how to proceed, starting from the most
|
||||
# recently pushed plan, in two stages:
|
||||
#
|
||||
# 1) Each plan is asked if it "explains" the stop. The first plan to claim the
|
||||
# stop wins. In scripted Thread Plans, this is done by returning True from
|
||||
# the "explains_stop method. This is how, for instance, control is returned
|
||||
# to the User when the "step-over" plan hits a breakpoint. The step-over
|
||||
# plan doesn't explain the breakpoint stop, so it returns false, and the
|
||||
# to the User when the "step-over" plan hits a breakpoint. The step-over
|
||||
# plan doesn't explain the breakpoint stop, so it returns false, and the
|
||||
# breakpoint hit is propagated up the stack to the "base" thread plan, which
|
||||
# is the one that handles random breakpoint hits.
|
||||
#
|
||||
@@ -50,10 +50,10 @@
|
||||
# the next time the thread continues.
|
||||
#
|
||||
# Note that deciding to return control to the user, and deciding your plan
|
||||
# is done, are orthgonal operations. You could set up the next phase of
|
||||
# is done, are orthgonal operations. You could set up the next phase of
|
||||
# stepping, and then return True from should_stop, and when the user next
|
||||
# "continued" the process your plan would resume control. Of course, the
|
||||
# user might also "step-over" or some other operation that would push a
|
||||
# user might also "step-over" or some other operation that would push a
|
||||
# different plan, which would take control till it was done.
|
||||
#
|
||||
# One other detail you should be aware of, if the plan below you on the
|
||||
@@ -71,8 +71,8 @@
|
||||
# This is useful, for instance, in the FinishPrintAndContinue plan. What might
|
||||
# happen here is that after continuing but before the finish is done, the program
|
||||
# could hit another breakpoint and stop. Then the user could use the step
|
||||
# command repeatedly until they leave the frame of interest by stepping.
|
||||
# In that case, the step plan is the one that will be responsible for stopping,
|
||||
# command repeatedly until they leave the frame of interest by stepping.
|
||||
# In that case, the step plan is the one that will be responsible for stopping,
|
||||
# and the finish plan won't be asked should_stop, it will just be asked if it
|
||||
# is stale. In this case, if the step_out plan that the FinishPrintAndContinue
|
||||
# plan is driving is stale, so is ours, and it is time to do our printing.
|
||||
@@ -80,7 +80,7 @@
|
||||
# Both examples show stepping through an address range for 20 bytes from the
|
||||
# current PC. The first one does it by single stepping and checking a condition.
|
||||
# It doesn't, however handle the case where you step into another frame while
|
||||
# still in the current range in the starting frame.
|
||||
# still in the current range in the starting frame.
|
||||
#
|
||||
# That is better handled in the second example by using the built-in StepOverRange
|
||||
# thread plan.
|
||||
@@ -95,76 +95,84 @@
|
||||
|
||||
import lldb
|
||||
|
||||
|
||||
class SimpleStep:
|
||||
def __init__ (self, thread_plan, dict):
|
||||
|
||||
def __init__(self, thread_plan, dict):
|
||||
self.thread_plan = thread_plan
|
||||
self.start_address = thread_plan.GetThread().GetFrameAtIndex(0).GetPC()
|
||||
|
||||
def explains_stop (self, event):
|
||||
|
||||
def explains_stop(self, event):
|
||||
# We are stepping, so if we stop for any other reason, it isn't
|
||||
# because of us.
|
||||
if self.thread_plan.GetThread().GetStopReason()== lldb.eStopReasonTrace:
|
||||
if self.thread_plan.GetThread().GetStopReason() == lldb.eStopReasonTrace:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def should_stop (self, event):
|
||||
|
||||
def should_stop(self, event):
|
||||
cur_pc = self.thread_plan.GetThread().GetFrameAtIndex(0).GetPC()
|
||||
|
||||
|
||||
if cur_pc < self.start_address or cur_pc >= self.start_address + 20:
|
||||
self.thread_plan.SetPlanComplete(True)
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def should_step (self):
|
||||
def should_step(self):
|
||||
return True
|
||||
|
||||
|
||||
class StepWithPlan:
|
||||
def __init__ (self, thread_plan, dict):
|
||||
|
||||
def __init__(self, thread_plan, dict):
|
||||
self.thread_plan = thread_plan
|
||||
self.start_address = thread_plan.GetThread().GetFrameAtIndex(0).GetPCAddress()
|
||||
self.step_thread_plan =thread_plan.QueueThreadPlanForStepOverRange(self.start_address, 20);
|
||||
self.step_thread_plan = thread_plan.QueueThreadPlanForStepOverRange(
|
||||
self.start_address, 20)
|
||||
|
||||
def explains_stop (self, event):
|
||||
def explains_stop(self, event):
|
||||
# Since all I'm doing is running a plan, I will only ever get askedthis
|
||||
# if myplan doesn't explain the stop, and in that caseI don'teither.
|
||||
return False
|
||||
|
||||
def should_stop (self, event):
|
||||
def should_stop(self, event):
|
||||
if self.step_thread_plan.IsPlanComplete():
|
||||
self.thread_plan.SetPlanComplete(True)
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def should_step (self):
|
||||
def should_step(self):
|
||||
return False
|
||||
|
||||
# Here's another example which does "step over" through the current function,
|
||||
# and when it stops at each line, it checks some condition (in this example the
|
||||
# value of a variable) and stops if that condition is true.
|
||||
|
||||
|
||||
class StepCheckingCondition:
|
||||
def __init__ (self, thread_plan, dict):
|
||||
|
||||
def __init__(self, thread_plan, dict):
|
||||
self.thread_plan = thread_plan
|
||||
self.start_frame = thread_plan.GetThread().GetFrameAtIndex(0)
|
||||
self.queue_next_plan()
|
||||
|
||||
def queue_next_plan (self):
|
||||
def queue_next_plan(self):
|
||||
cur_frame = self.thread_plan.GetThread().GetFrameAtIndex(0)
|
||||
cur_line_entry = cur_frame.GetLineEntry()
|
||||
start_address = cur_line_entry.GetStartAddress()
|
||||
end_address = cur_line_entry.GetEndAddress()
|
||||
line_range = end_address.GetFileAddress() - start_address.GetFileAddress()
|
||||
self.step_thread_plan = self.thread_plan.QueueThreadPlanForStepOverRange(start_address, line_range)
|
||||
self.step_thread_plan = self.thread_plan.QueueThreadPlanForStepOverRange(
|
||||
start_address, line_range)
|
||||
|
||||
def explains_stop (self, event):
|
||||
def explains_stop(self, event):
|
||||
# We are stepping, so if we stop for any other reason, it isn't
|
||||
# because of us.
|
||||
return False
|
||||
|
||||
def should_stop (self, event):
|
||||
|
||||
def should_stop(self, event):
|
||||
if not self.step_thread_plan.IsPlanComplete():
|
||||
return False
|
||||
|
||||
@@ -182,7 +190,7 @@ class StepCheckingCondition:
|
||||
return True
|
||||
|
||||
error = lldb.SBError()
|
||||
a_value = a_var.GetValueAsSigned (error)
|
||||
a_value = a_var.GetValueAsSigned(error)
|
||||
if not error.Success():
|
||||
print "A value was not good."
|
||||
return True
|
||||
@@ -194,7 +202,7 @@ class StepCheckingCondition:
|
||||
self.queue_next_plan()
|
||||
return False
|
||||
|
||||
def should_step (self):
|
||||
def should_step(self):
|
||||
return True
|
||||
|
||||
# Here's an example that steps out of the current frame, gathers some information
|
||||
@@ -202,29 +210,32 @@ class StepCheckingCondition:
|
||||
# plans are not a safe place to call lldb command-line commands, so the information
|
||||
# is gathered through SB API calls.
|
||||
|
||||
|
||||
class FinishPrintAndContinue:
|
||||
def __init__ (self, thread_plan, dict):
|
||||
|
||||
def __init__(self, thread_plan, dict):
|
||||
self.thread_plan = thread_plan
|
||||
self.step_out_thread_plan = thread_plan.QueueThreadPlanForStepOut(0, True)
|
||||
self.step_out_thread_plan = thread_plan.QueueThreadPlanForStepOut(
|
||||
0, True)
|
||||
self.thread = self.thread_plan.GetThread()
|
||||
|
||||
def is_stale (self):
|
||||
def is_stale(self):
|
||||
if self.step_out_thread_plan.IsPlanStale():
|
||||
self.do_print()
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def explains_stop (self, event):
|
||||
def explains_stop(self, event):
|
||||
return False
|
||||
|
||||
def should_stop (self, event):
|
||||
if self.step_out_thread_plan.IsPlanComplete():
|
||||
def should_stop(self, event):
|
||||
if self.step_out_thread_plan.IsPlanComplete():
|
||||
self.do_print()
|
||||
self.thread_plan.SetPlanComplete(True)
|
||||
return False
|
||||
|
||||
def do_print (self):
|
||||
def do_print(self):
|
||||
frame_0 = self.thread.frames[0]
|
||||
rax_value = frame_0.FindRegister("rax")
|
||||
if rax_value.GetError().Success():
|
||||
|
||||
@@ -3,14 +3,16 @@
|
||||
import lldb
|
||||
import shlex
|
||||
|
||||
|
||||
@lldb.command("shadow")
|
||||
def check_shadow_command(debugger, command, exe_ctx, result, dict):
|
||||
'''Check the currently selected stack frame for shadowed variables'''
|
||||
process = exe_ctx.GetProcess()
|
||||
state = process.GetState()
|
||||
if state != lldb.eStateStopped:
|
||||
print >>result, "process must be stopped, state is %s" % lldb.SBDebugger.StateAsCString(state)
|
||||
return
|
||||
print >>result, "process must be stopped, state is %s" % lldb.SBDebugger.StateAsCString(
|
||||
state)
|
||||
return
|
||||
frame = exe_ctx.GetFrame()
|
||||
if not frame:
|
||||
print >>result, "invalid frame"
|
||||
@@ -18,10 +20,10 @@ def check_shadow_command(debugger, command, exe_ctx, result, dict):
|
||||
# Parse command line args
|
||||
command_args = shlex.split(command)
|
||||
# TODO: add support for using arguments that are passed to this command...
|
||||
|
||||
|
||||
# Make a dictionary of variable name to "SBBlock and SBValue"
|
||||
shadow_dict = {}
|
||||
|
||||
|
||||
num_shadowed_variables = 0
|
||||
# Get the deepest most block from the current frame
|
||||
block = frame.GetBlock()
|
||||
@@ -40,7 +42,7 @@ def check_shadow_command(debugger, command, exe_ctx, result, dict):
|
||||
shadow_dict[block_var_name].append(block_var)
|
||||
else:
|
||||
shadow_dict[block_var_name] = [block_var]
|
||||
# Get the parent block and continue
|
||||
# Get the parent block and continue
|
||||
block = block.GetParent()
|
||||
|
||||
num_shadowed_variables = 0
|
||||
@@ -54,4 +56,3 @@ def check_shadow_command(debugger, command, exe_ctx, result, dict):
|
||||
print >>result, str(shadow_var.GetDeclaration())
|
||||
if num_shadowed_variables == 0:
|
||||
print >>result, 'no variables are shadowed'
|
||||
|
||||
|
||||
@@ -3,15 +3,17 @@
|
||||
import lldb
|
||||
import shlex
|
||||
|
||||
|
||||
def dump_module_sources(module, result):
|
||||
if module:
|
||||
print >> result, "Module: %s" % (module.file)
|
||||
for compile_unit in module.compile_units:
|
||||
if compile_unit.file:
|
||||
print >> result, " %s" % (compile_unit.file)
|
||||
|
||||
|
||||
|
||||
def info_sources(debugger, command, result, dict):
|
||||
description='''This command will dump all compile units in any modules that are listed as arguments, or for all modules if no arguments are supplied.'''
|
||||
description = '''This command will dump all compile units in any modules that are listed as arguments, or for all modules if no arguments are supplied.'''
|
||||
module_names = shlex.split(command)
|
||||
target = debugger.GetSelectedTarget()
|
||||
if module_names:
|
||||
@@ -20,9 +22,10 @@ def info_sources(debugger, command, result, dict):
|
||||
else:
|
||||
for module in target.modules:
|
||||
dump_module_sources(module, result)
|
||||
|
||||
|
||||
def __lldb_init_module (debugger, dict):
|
||||
|
||||
|
||||
def __lldb_init_module(debugger, dict):
|
||||
# Add any commands contained in this module to LLDB
|
||||
debugger.HandleCommand('command script add -f sources.info_sources info_sources')
|
||||
debugger.HandleCommand(
|
||||
'command script add -f sources.info_sources info_sources')
|
||||
print 'The "info_sources" command has been installed, type "help info_sources" or "info_sources --help" for detailed help.'
|
||||
|
||||
@@ -5,20 +5,28 @@ import commands
|
||||
import optparse
|
||||
import shlex
|
||||
|
||||
|
||||
def stack_frames(debugger, command, result, dict):
|
||||
command_args = shlex.split(command)
|
||||
usage = "usage: %prog [options] <PATH> [PATH ...]"
|
||||
description='''This command will enumerate all stack frames, print the stack size for each, and print an aggregation of which functions have the largest stack frame sizes at the end.'''
|
||||
parser = optparse.OptionParser(description=description, prog='ls',usage=usage)
|
||||
parser.add_option('-v', '--verbose', action='store_true', dest='verbose', help='display verbose debug info', default=False)
|
||||
description = '''This command will enumerate all stack frames, print the stack size for each, and print an aggregation of which functions have the largest stack frame sizes at the end.'''
|
||||
parser = optparse.OptionParser(
|
||||
description=description, prog='ls', usage=usage)
|
||||
parser.add_option(
|
||||
'-v',
|
||||
'--verbose',
|
||||
action='store_true',
|
||||
dest='verbose',
|
||||
help='display verbose debug info',
|
||||
default=False)
|
||||
try:
|
||||
(options, args) = parser.parse_args(command_args)
|
||||
except:
|
||||
return
|
||||
|
||||
|
||||
target = debugger.GetSelectedTarget()
|
||||
process = target.GetProcess()
|
||||
|
||||
|
||||
frame_info = {}
|
||||
for thread in process:
|
||||
last_frame = None
|
||||
@@ -28,12 +36,13 @@ def stack_frames(debugger, command, result, dict):
|
||||
frame_size = 0
|
||||
if frame.idx == 1:
|
||||
if frame.fp == last_frame.fp:
|
||||
# No frame one the first frame (might be right at the entry point)
|
||||
# No frame one the first frame (might be right at the
|
||||
# entry point)
|
||||
first_frame_size = 0
|
||||
frame_size = frame.fp - frame.sp
|
||||
else:
|
||||
# First frame that has a valid size
|
||||
first_frame_size = last_frame.fp - last_frame.sp
|
||||
first_frame_size = last_frame.fp - last_frame.sp
|
||||
print "<%#7x> %s" % (first_frame_size, last_frame)
|
||||
if first_frame_size:
|
||||
name = last_frame.name
|
||||
@@ -43,7 +52,7 @@ def stack_frames(debugger, command, result, dict):
|
||||
frame_info[name] += first_frame_size
|
||||
else:
|
||||
# Second or higher frame
|
||||
frame_size = frame.fp - last_frame.fp
|
||||
frame_size = frame.fp - last_frame.fp
|
||||
print "<%#7x> %s" % (frame_size, frame)
|
||||
if frame_size > 0:
|
||||
name = frame.name
|
||||
@@ -53,7 +62,8 @@ def stack_frames(debugger, command, result, dict):
|
||||
frame_info[name] += frame_size
|
||||
last_frame = frame
|
||||
print frame_info
|
||||
|
||||
|
||||
lldb.debugger.HandleCommand("command script add -f stacks.stack_frames stack_frames")
|
||||
print "A new command called 'stack_frames' was added, type 'stack_frames --help' for more information."
|
||||
|
||||
lldb.debugger.HandleCommand(
|
||||
"command script add -f stacks.stack_frames stack_frames")
|
||||
print "A new command called 'stack_frames' was added, type 'stack_frames --help' for more information."
|
||||
|
||||
@@ -11,13 +11,13 @@
|
||||
# "crashlog" command installed, type "crashlog --help" for detailed help
|
||||
# (lldb) crashlog ~/Library/Logs/DiagnosticReports/a.crash
|
||||
#
|
||||
# The benefit of running the crashlog command inside lldb in the
|
||||
# embedded python interpreter is when the command completes, there
|
||||
# The benefit of running the crashlog command inside lldb in the
|
||||
# embedded python interpreter is when the command completes, there
|
||||
# will be a target with all of the files loaded at the locations
|
||||
# described in the crash log. Only the files that have stack frames
|
||||
# in the backtrace will be loaded unless the "--load-all" option
|
||||
# has been specified. This allows users to explore the program in the
|
||||
# state it was in right at crash time.
|
||||
# state it was in right at crash time.
|
||||
#
|
||||
# On MacOSX csh, tcsh:
|
||||
# ( setenv PYTHONPATH /path/to/LLDB.framework/Resources/Python ; ./crashlog.py ~/Library/Logs/DiagnosticReports/a.crash )
|
||||
@@ -37,16 +37,23 @@ import sys
|
||||
import time
|
||||
import uuid
|
||||
|
||||
|
||||
class Address:
|
||||
"""Class that represents an address that will be symbolicated"""
|
||||
|
||||
def __init__(self, target, load_addr):
|
||||
self.target = target
|
||||
self.load_addr = load_addr # The load address that this object represents
|
||||
self.so_addr = None # the resolved lldb.SBAddress (if any), named so_addr for section/offset address
|
||||
self.sym_ctx = None # The cached symbol context for this address
|
||||
self.description = None # Any original textual description of this address to be used as a backup in case symbolication fails
|
||||
self.symbolication = None # The cached symbolicated string that describes this address
|
||||
self.load_addr = load_addr # The load address that this object represents
|
||||
# the resolved lldb.SBAddress (if any), named so_addr for
|
||||
# section/offset address
|
||||
self.so_addr = None
|
||||
self.sym_ctx = None # The cached symbol context for this address
|
||||
# Any original textual description of this address to be used as a
|
||||
# backup in case symbolication fails
|
||||
self.description = None
|
||||
self.symbolication = None # The cached symbolicated string that describes this address
|
||||
self.inlined = False
|
||||
|
||||
def __str__(self):
|
||||
s = "%#16.16x" % (self.load_addr)
|
||||
if self.symbolication:
|
||||
@@ -58,18 +65,19 @@ class Address:
|
||||
return s
|
||||
|
||||
def resolve_addr(self):
|
||||
if self.so_addr == None:
|
||||
self.so_addr = self.target.ResolveLoadAddress (self.load_addr)
|
||||
if self.so_addr is None:
|
||||
self.so_addr = self.target.ResolveLoadAddress(self.load_addr)
|
||||
return self.so_addr
|
||||
|
||||
def is_inlined(self):
|
||||
return self.inlined
|
||||
|
||||
|
||||
def get_symbol_context(self):
|
||||
if self.sym_ctx == None:
|
||||
if self.sym_ctx is None:
|
||||
sb_addr = self.resolve_addr()
|
||||
if sb_addr:
|
||||
self.sym_ctx = self.target.ResolveSymbolContextForAddress (sb_addr, lldb.eSymbolContextEverything)
|
||||
self.sym_ctx = self.target.ResolveSymbolContextForAddress(
|
||||
sb_addr, lldb.eSymbolContextEverything)
|
||||
else:
|
||||
self.sym_ctx = lldb.SBSymbolContext()
|
||||
return self.sym_ctx
|
||||
@@ -82,9 +90,9 @@ class Address:
|
||||
return function.GetInstructions(self.target)
|
||||
return sym_ctx.GetSymbol().GetInstructions(self.target)
|
||||
return None
|
||||
|
||||
def symbolicate(self, verbose = False):
|
||||
if self.symbolication == None:
|
||||
|
||||
def symbolicate(self, verbose=False):
|
||||
if self.symbolication is None:
|
||||
self.symbolication = ''
|
||||
self.inlined = False
|
||||
sym_ctx = self.get_symbol_context()
|
||||
@@ -101,27 +109,32 @@ class Address:
|
||||
block = sym_ctx.GetBlock()
|
||||
line_entry = sym_ctx.GetLineEntry()
|
||||
symbol = sym_ctx.GetSymbol()
|
||||
inlined_block = block.GetContainingInlinedBlock();
|
||||
inlined_block = block.GetContainingInlinedBlock()
|
||||
if function:
|
||||
self.symbolication += function.GetName()
|
||||
|
||||
if inlined_block:
|
||||
self.inlined = True
|
||||
self.symbolication += ' [inlined] ' + inlined_block.GetInlinedName();
|
||||
block_range_idx = inlined_block.GetRangeIndexForBlockAddress (self.so_addr)
|
||||
self.symbolication += ' [inlined] ' + \
|
||||
inlined_block.GetInlinedName()
|
||||
block_range_idx = inlined_block.GetRangeIndexForBlockAddress(
|
||||
self.so_addr)
|
||||
if block_range_idx < lldb.UINT32_MAX:
|
||||
block_range_start_addr = inlined_block.GetRangeStartAddress (block_range_idx)
|
||||
function_start_load_addr = block_range_start_addr.GetLoadAddress (self.target)
|
||||
block_range_start_addr = inlined_block.GetRangeStartAddress(
|
||||
block_range_idx)
|
||||
function_start_load_addr = block_range_start_addr.GetLoadAddress(
|
||||
self.target)
|
||||
if function_start_load_addr == -1:
|
||||
function_start_load_addr = function.GetStartAddress().GetLoadAddress (self.target)
|
||||
function_start_load_addr = function.GetStartAddress().GetLoadAddress(self.target)
|
||||
elif symbol:
|
||||
self.symbolication += symbol.GetName()
|
||||
function_start_load_addr = symbol.GetStartAddress().GetLoadAddress (self.target)
|
||||
function_start_load_addr = symbol.GetStartAddress().GetLoadAddress(self.target)
|
||||
else:
|
||||
self.symbolication = ''
|
||||
return False
|
||||
|
||||
# Dump the offset from the current function or symbol if it is non zero
|
||||
# Dump the offset from the current function or symbol if it
|
||||
# is non zero
|
||||
function_offset = self.load_addr - function_start_load_addr
|
||||
if function_offset > 0:
|
||||
self.symbolication += " + %u" % (function_offset)
|
||||
@@ -135,38 +148,44 @@ class Address:
|
||||
self.symbolication += ' at %s' % line_entry.GetFileSpec()
|
||||
else:
|
||||
self.symbolication += ' at %s' % line_entry.GetFileSpec().GetFilename()
|
||||
self.symbolication += ':%u' % line_entry.GetLine ()
|
||||
self.symbolication += ':%u' % line_entry.GetLine()
|
||||
column = line_entry.GetColumn()
|
||||
if column > 0:
|
||||
self.symbolication += ':%u' % column
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
class Section:
|
||||
"""Class that represents an load address range"""
|
||||
sect_info_regex = re.compile('(?P<name>[^=]+)=(?P<range>.*)')
|
||||
addr_regex = re.compile('^\s*(?P<start>0x[0-9A-Fa-f]+)\s*$')
|
||||
range_regex = re.compile('^\s*(?P<start>0x[0-9A-Fa-f]+)\s*(?P<op>[-+])\s*(?P<end>0x[0-9A-Fa-f]+)\s*$')
|
||||
range_regex = re.compile(
|
||||
'^\s*(?P<start>0x[0-9A-Fa-f]+)\s*(?P<op>[-+])\s*(?P<end>0x[0-9A-Fa-f]+)\s*$')
|
||||
|
||||
def __init__(self, start_addr = None, end_addr = None, name = None):
|
||||
def __init__(self, start_addr=None, end_addr=None, name=None):
|
||||
self.start_addr = start_addr
|
||||
self.end_addr = end_addr
|
||||
self.name = name
|
||||
|
||||
|
||||
@classmethod
|
||||
def InitWithSBTargetAndSBSection(cls, target, section):
|
||||
sect_load_addr = section.GetLoadAddress(target)
|
||||
if sect_load_addr != lldb.LLDB_INVALID_ADDRESS:
|
||||
obj = cls(sect_load_addr, sect_load_addr + section.size, section.name)
|
||||
obj = cls(
|
||||
sect_load_addr,
|
||||
sect_load_addr +
|
||||
section.size,
|
||||
section.name)
|
||||
return obj
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def contains(self, addr):
|
||||
return self.start_addr <= addr and addr < self.end_addr;
|
||||
|
||||
return self.start_addr <= addr and addr < self.end_addr
|
||||
|
||||
def set_from_string(self, s):
|
||||
match = self.sect_info_regex.match (s)
|
||||
match = self.sect_info_regex.match(s)
|
||||
if match:
|
||||
self.name = match.group('name')
|
||||
range_str = match.group('range')
|
||||
@@ -192,22 +211,24 @@ class Section:
|
||||
print '<name>=<base>-<end> __TEXT=0x123000-0x124000 Section from base address and end address'
|
||||
print '<name>=<base>+<size> __TEXT=0x123000+0x1000 Section from base address and size'
|
||||
return False
|
||||
|
||||
|
||||
def __str__(self):
|
||||
if self.name:
|
||||
if self.end_addr != None:
|
||||
if self.start_addr != None:
|
||||
return "%s=[0x%16.16x - 0x%16.16x)" % (self.name, self.start_addr, self.end_addr)
|
||||
if self.end_addr is not None:
|
||||
if self.start_addr is not None:
|
||||
return "%s=[0x%16.16x - 0x%16.16x)" % (
|
||||
self.name, self.start_addr, self.end_addr)
|
||||
else:
|
||||
if self.start_addr != None:
|
||||
if self.start_addr is not None:
|
||||
return "%s=0x%16.16x" % (self.name, self.start_addr)
|
||||
return self.name
|
||||
return "<invalid>"
|
||||
|
||||
|
||||
|
||||
class Image:
|
||||
"""A class that represents an executable image and any associated data"""
|
||||
|
||||
def __init__(self, path, uuid = None):
|
||||
|
||||
def __init__(self, path, uuid=None):
|
||||
self.path = path
|
||||
self.resolved_path = None
|
||||
self.resolved = False
|
||||
@@ -220,7 +241,7 @@ class Image:
|
||||
self.module = None
|
||||
self.symfile = None
|
||||
self.slide = None
|
||||
|
||||
|
||||
@classmethod
|
||||
def InitWithSBTargetAndSBModule(cls, target, module):
|
||||
'''Initialize this Image object with a module from a target.'''
|
||||
@@ -229,15 +250,16 @@ class Image:
|
||||
obj.resolved = True
|
||||
obj.arch = module.triple
|
||||
for section in module.sections:
|
||||
symb_section = Section.InitWithSBTargetAndSBSection(target, section)
|
||||
symb_section = Section.InitWithSBTargetAndSBSection(
|
||||
target, section)
|
||||
if symb_section:
|
||||
obj.section_infos.append (symb_section)
|
||||
obj.section_infos.append(symb_section)
|
||||
obj.arch = module.triple
|
||||
obj.module = module
|
||||
obj.symfile = None
|
||||
obj.slide = None
|
||||
return obj
|
||||
|
||||
|
||||
def dump(self, prefix):
|
||||
print "%s%s" % (prefix, self)
|
||||
|
||||
@@ -254,7 +276,7 @@ class Image:
|
||||
print 'module = %s' % (self.module)
|
||||
print 'symfile = "%s"' % (self.symfile)
|
||||
print 'slide = %i (0x%x)' % (self.slide, self.slide)
|
||||
|
||||
|
||||
def __str__(self):
|
||||
s = ''
|
||||
if self.uuid:
|
||||
@@ -268,15 +290,15 @@ class Image:
|
||||
s += "%s " % (resolved_path)
|
||||
for section_info in self.section_infos:
|
||||
s += ", %s" % (section_info)
|
||||
if self.slide != None:
|
||||
if self.slide is not None:
|
||||
s += ', slide = 0x%16.16x' % self.slide
|
||||
return s
|
||||
|
||||
return s
|
||||
|
||||
def add_section(self, section):
|
||||
#print "added '%s' to '%s'" % (section, self.path)
|
||||
self.section_infos.append (section)
|
||||
|
||||
def get_section_containing_load_addr (self, load_addr):
|
||||
# print "added '%s' to '%s'" % (section, self.path)
|
||||
self.section_infos.append(section)
|
||||
|
||||
def get_section_containing_load_addr(self, load_addr):
|
||||
for section_info in self.section_infos:
|
||||
if section_info.contains(load_addr):
|
||||
return section_info
|
||||
@@ -299,13 +321,13 @@ class Image:
|
||||
if self.symfile:
|
||||
return os.path.basename(self.symfile)
|
||||
return None
|
||||
|
||||
|
||||
def has_section_load_info(self):
|
||||
return self.section_infos or self.slide != None
|
||||
|
||||
return self.section_infos or self.slide is not None
|
||||
|
||||
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
|
||||
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
|
||||
# set the section load addresses
|
||||
if self.has_section_load_info():
|
||||
@@ -315,9 +337,11 @@ class Image:
|
||||
num_sections_loaded = 0
|
||||
for section_info in self.section_infos:
|
||||
if section_info.name:
|
||||
section = self.module.FindSection (section_info.name)
|
||||
section = self.module.FindSection(
|
||||
section_info.name)
|
||||
if section:
|
||||
error = target.SetSectionLoadAddress (section, section_info.start_addr)
|
||||
error = target.SetSectionLoadAddress(
|
||||
section, section_info.start_addr)
|
||||
if error.Success():
|
||||
num_sections_loaded += 1
|
||||
else:
|
||||
@@ -325,11 +349,13 @@ class Image:
|
||||
else:
|
||||
return 'error: unable to find the section named "%s"' % section_info.name
|
||||
else:
|
||||
return 'error: unable to find "%s" section in "%s"' % (range.name, self.get_resolved_path())
|
||||
return 'error: unable to find "%s" section in "%s"' % (
|
||||
range.name, self.get_resolved_path())
|
||||
if num_sections_loaded == 0:
|
||||
return 'error: no sections were successfully loaded'
|
||||
else:
|
||||
err = target.SetModuleLoadAddress(self.module, self.slide)
|
||||
err = target.SetModuleLoadAddress(
|
||||
self.module, self.slide)
|
||||
if err.Fail():
|
||||
return err.GetCString()
|
||||
return None
|
||||
@@ -339,30 +365,33 @@ class Image:
|
||||
return 'error: invalid target'
|
||||
else:
|
||||
return 'error: no section infos'
|
||||
|
||||
|
||||
def add_module(self, target):
|
||||
'''Add the Image described in this object to "target" and load the sections if "load" is True.'''
|
||||
if target:
|
||||
# Try and find using UUID only first so that paths need not match up
|
||||
# Try and find using UUID only first so that paths need not match
|
||||
# up
|
||||
uuid_str = self.get_normalized_uuid_string()
|
||||
if uuid_str:
|
||||
self.module = target.AddModule (None, None, uuid_str)
|
||||
self.module = target.AddModule(None, None, uuid_str)
|
||||
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()
|
||||
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:
|
||||
return 'error: unable to get module for (%s) "%s"' % (self.arch, self.get_resolved_path())
|
||||
return 'error: unable to get module for (%s) "%s"' % (
|
||||
self.arch, self.get_resolved_path())
|
||||
if self.has_section_load_info():
|
||||
return self.load_module(target)
|
||||
else:
|
||||
return None # No sections, the module was added to the target, so success
|
||||
return None # No sections, the module was added to the target, so success
|
||||
else:
|
||||
return 'error: invalid target'
|
||||
|
||||
def locate_module_and_debug_symbols (self):
|
||||
|
||||
def locate_module_and_debug_symbols(self):
|
||||
# By default, just use the paths that were supplied in:
|
||||
# self.path
|
||||
# self.resolved_path
|
||||
@@ -371,7 +400,7 @@ class Image:
|
||||
# Subclasses can inherit from this class and override this function
|
||||
self.resolved = True
|
||||
return True
|
||||
|
||||
|
||||
def get_uuid(self):
|
||||
if not self.uuid and self.module:
|
||||
self.uuid = uuid.UUID(self.module.GetUUIDString())
|
||||
@@ -387,12 +416,13 @@ class Image:
|
||||
if self.unavailable:
|
||||
return None
|
||||
|
||||
if self.locate_module_and_debug_symbols ():
|
||||
resolved_path = self.get_resolved_path();
|
||||
path_spec = lldb.SBFileSpec (resolved_path)
|
||||
if self.locate_module_and_debug_symbols():
|
||||
resolved_path = self.get_resolved_path()
|
||||
path_spec = lldb.SBFileSpec(resolved_path)
|
||||
#result.PutCString ('plist[%s] = %s' % (uuid, self.plist))
|
||||
error = lldb.SBError()
|
||||
target = lldb.debugger.CreateTarget (resolved_path, self.arch, None, False, error);
|
||||
target = lldb.debugger.CreateTarget(
|
||||
resolved_path, self.arch, None, False, error)
|
||||
if target:
|
||||
self.module = target.FindModule(path_spec)
|
||||
if self.has_section_load_info():
|
||||
@@ -405,20 +435,21 @@ class Image:
|
||||
else:
|
||||
print 'error: unable to locate main executable (%s) "%s"' % (self.arch, self.path)
|
||||
return None
|
||||
|
||||
|
||||
|
||||
class Symbolicator:
|
||||
|
||||
def __init__(self):
|
||||
"""A class the represents the information needed to symbolicate addresses in a program"""
|
||||
self.target = None
|
||||
self.images = list() # a list of images to be used when symbolicating
|
||||
self.images = list() # a list of images to be used when symbolicating
|
||||
self.addr_mask = 0xffffffffffffffff
|
||||
|
||||
|
||||
@classmethod
|
||||
def InitWithSBTarget(cls, target):
|
||||
obj = cls()
|
||||
obj.target = target
|
||||
obj.images = list();
|
||||
obj.images = list()
|
||||
triple = target.triple
|
||||
if triple:
|
||||
arch = triple.split('-')[0]
|
||||
@@ -429,7 +460,7 @@ class Symbolicator:
|
||||
image = Image.InitWithSBTargetAndSBModule(target, module)
|
||||
obj.images.append(image)
|
||||
return obj
|
||||
|
||||
|
||||
def __str__(self):
|
||||
s = "Symbolicator:\n"
|
||||
if self.target:
|
||||
@@ -441,7 +472,7 @@ class Symbolicator:
|
||||
for image in self.images:
|
||||
s += ' %s\n' % (image)
|
||||
return s
|
||||
|
||||
|
||||
def find_images_with_identifier(self, identifier):
|
||||
images = list()
|
||||
for image in self.images:
|
||||
@@ -454,20 +485,20 @@ class Symbolicator:
|
||||
if regex.match(image.identifier):
|
||||
images.append(image)
|
||||
return images
|
||||
|
||||
|
||||
def find_image_containing_load_addr(self, load_addr):
|
||||
for image in self.images:
|
||||
if image.get_section_containing_load_addr (load_addr):
|
||||
if image.get_section_containing_load_addr(load_addr):
|
||||
return image
|
||||
return None
|
||||
|
||||
|
||||
def create_target(self):
|
||||
if self.target:
|
||||
return self.target
|
||||
|
||||
if self.images:
|
||||
for image in self.images:
|
||||
self.target = image.create_target ()
|
||||
self.target = image.create_target()
|
||||
if self.target:
|
||||
if self.target.GetAddressByteSize() == 4:
|
||||
triple = self.target.triple
|
||||
@@ -477,9 +508,8 @@ class Symbolicator:
|
||||
self.addr_mask = 0xfffffffffffffffe
|
||||
return self.target
|
||||
return None
|
||||
|
||||
|
||||
def symbolicate(self, load_addr, verbose = False):
|
||||
|
||||
def symbolicate(self, load_addr, verbose=False):
|
||||
if not self.target:
|
||||
self.create_target()
|
||||
if self.target:
|
||||
@@ -493,51 +523,60 @@ class Symbolicator:
|
||||
# that a load address belongs to and lazily load its module in the
|
||||
# target, but we shouldn't do any of this if we have a live process
|
||||
if not live_process:
|
||||
image = self.find_image_containing_load_addr (load_addr)
|
||||
image = self.find_image_containing_load_addr(load_addr)
|
||||
if image:
|
||||
image.add_module (self.target)
|
||||
image.add_module(self.target)
|
||||
symbolicated_address = Address(self.target, load_addr)
|
||||
if symbolicated_address.symbolicate (verbose):
|
||||
if symbolicated_address.symbolicate(verbose):
|
||||
if symbolicated_address.so_addr:
|
||||
symbolicated_addresses = list()
|
||||
symbolicated_addresses.append(symbolicated_address)
|
||||
# See if we were able to reconstruct anything?
|
||||
while 1:
|
||||
while True:
|
||||
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:
|
||||
break
|
||||
if not inlined_parent_so_addr:
|
||||
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.so_addr = inlined_parent_so_addr
|
||||
symbolicated_address.symbolicate (verbose)
|
||||
|
||||
symbolicated_address.symbolicate(verbose)
|
||||
|
||||
# push the new frame onto the new frame stack
|
||||
symbolicated_addresses.append (symbolicated_address)
|
||||
|
||||
symbolicated_addresses.append(symbolicated_address)
|
||||
|
||||
if symbolicated_addresses:
|
||||
return symbolicated_addresses
|
||||
else:
|
||||
print 'error: no target in Symbolicator'
|
||||
return None
|
||||
|
||||
|
||||
def disassemble_instructions (target, instructions, pc, insts_before_pc, insts_after_pc, non_zeroeth_frame):
|
||||
|
||||
|
||||
def disassemble_instructions(
|
||||
target,
|
||||
instructions,
|
||||
pc,
|
||||
insts_before_pc,
|
||||
insts_after_pc,
|
||||
non_zeroeth_frame):
|
||||
lines = list()
|
||||
pc_index = -1
|
||||
comment_column = 50
|
||||
for inst_idx, inst in enumerate(instructions):
|
||||
inst_pc = inst.GetAddress().GetLoadAddress(target);
|
||||
inst_pc = inst.GetAddress().GetLoadAddress(target)
|
||||
if pc == inst_pc:
|
||||
pc_index = inst_idx
|
||||
mnemonic = inst.GetMnemonic (target)
|
||||
operands = inst.GetOperands (target)
|
||||
comment = inst.GetComment (target)
|
||||
mnemonic = inst.GetMnemonic(target)
|
||||
operands = inst.GetOperands(target)
|
||||
comment = inst.GetComment(target)
|
||||
#data = inst.GetData (target)
|
||||
lines.append ("%#16.16x: %8s %s" % (inst_pc, mnemonic, operands))
|
||||
lines.append("%#16.16x: %8s %s" % (inst_pc, mnemonic, operands))
|
||||
if comment:
|
||||
line_len = len(lines[-1])
|
||||
if line_len < comment_column:
|
||||
@@ -545,7 +584,8 @@ def disassemble_instructions (target, instructions, pc, insts_before_pc, insts_a
|
||||
lines[-1] += "; %s" % comment
|
||||
|
||||
if pc_index >= 0:
|
||||
# If we are disassembling the non-zeroeth frame, we need to backup the PC by 1
|
||||
# If we are disassembling the non-zeroeth frame, we need to backup the
|
||||
# PC by 1
|
||||
if non_zeroeth_frame and pc_index > 0:
|
||||
pc_index = pc_index - 1
|
||||
if insts_before_pc == -1:
|
||||
@@ -560,81 +600,128 @@ def disassemble_instructions (target, instructions, pc, insts_before_pc, insts_a
|
||||
end_idx = pc_index + insts_after_pc
|
||||
if end_idx > inst_idx:
|
||||
end_idx = inst_idx
|
||||
for i in range(start_idx, end_idx+1):
|
||||
for i in range(start_idx, end_idx + 1):
|
||||
if i == pc_index:
|
||||
print ' -> ', lines[i]
|
||||
else:
|
||||
print ' ', lines[i]
|
||||
|
||||
def print_module_section_data (section):
|
||||
|
||||
def print_module_section_data(section):
|
||||
print section
|
||||
section_data = section.GetSectionData()
|
||||
if section_data:
|
||||
ostream = lldb.SBStream()
|
||||
section_data.GetDescription (ostream, section.GetFileAddress())
|
||||
section_data.GetDescription(ostream, section.GetFileAddress())
|
||||
print ostream.GetData()
|
||||
|
||||
def print_module_section (section, depth):
|
||||
|
||||
def print_module_section(section, depth):
|
||||
print section
|
||||
if depth > 0:
|
||||
num_sub_sections = section.GetNumSubSections()
|
||||
for sect_idx in range(num_sub_sections):
|
||||
print_module_section (section.GetSubSectionAtIndex(sect_idx), depth - 1)
|
||||
print_module_section(
|
||||
section.GetSubSectionAtIndex(sect_idx), depth - 1)
|
||||
|
||||
def print_module_sections (module, depth):
|
||||
|
||||
def print_module_sections(module, depth):
|
||||
for sect in module.section_iter():
|
||||
print_module_section (sect, depth)
|
||||
print_module_section(sect, depth)
|
||||
|
||||
def print_module_symbols (module):
|
||||
|
||||
def print_module_symbols(module):
|
||||
for sym in module:
|
||||
print sym
|
||||
|
||||
|
||||
def Symbolicate(command_args):
|
||||
|
||||
|
||||
usage = "usage: %prog [options] <addr1> [addr2 ...]"
|
||||
description='''Symbolicate one or more addresses using LLDB's python scripting API..'''
|
||||
parser = optparse.OptionParser(description=description, prog='crashlog.py',usage=usage)
|
||||
parser.add_option('-v', '--verbose', action='store_true', dest='verbose', help='display verbose debug info', default=False)
|
||||
parser.add_option('-p', '--platform', type='string', metavar='platform', dest='platform', help='Specify the platform to use when creating the debug target. Valid values include "localhost", "darwin-kernel", "ios-simulator", "remote-freebsd", "remote-macosx", "remote-ios", "remote-linux".')
|
||||
parser.add_option('-f', '--file', type='string', metavar='file', dest='file', help='Specify a file to use when symbolicating')
|
||||
parser.add_option('-a', '--arch', type='string', metavar='arch', dest='arch', help='Specify a architecture to use when symbolicating')
|
||||
parser.add_option('-s', '--slide', type='int', metavar='slide', dest='slide', help='Specify the slide to use on the file specified with the --file option', default=None)
|
||||
parser.add_option('--section', type='string', action='append', dest='section_strings', help='specify <sect-name>=<start-addr> or <sect-name>=<start-addr>-<end-addr>')
|
||||
description = '''Symbolicate one or more addresses using LLDB's python scripting API..'''
|
||||
parser = optparse.OptionParser(
|
||||
description=description,
|
||||
prog='crashlog.py',
|
||||
usage=usage)
|
||||
parser.add_option(
|
||||
'-v',
|
||||
'--verbose',
|
||||
action='store_true',
|
||||
dest='verbose',
|
||||
help='display verbose debug info',
|
||||
default=False)
|
||||
parser.add_option(
|
||||
'-p',
|
||||
'--platform',
|
||||
type='string',
|
||||
metavar='platform',
|
||||
dest='platform',
|
||||
help='Specify the platform to use when creating the debug target. Valid values include "localhost", "darwin-kernel", "ios-simulator", "remote-freebsd", "remote-macosx", "remote-ios", "remote-linux".')
|
||||
parser.add_option(
|
||||
'-f',
|
||||
'--file',
|
||||
type='string',
|
||||
metavar='file',
|
||||
dest='file',
|
||||
help='Specify a file to use when symbolicating')
|
||||
parser.add_option(
|
||||
'-a',
|
||||
'--arch',
|
||||
type='string',
|
||||
metavar='arch',
|
||||
dest='arch',
|
||||
help='Specify a architecture to use when symbolicating')
|
||||
parser.add_option(
|
||||
'-s',
|
||||
'--slide',
|
||||
type='int',
|
||||
metavar='slide',
|
||||
dest='slide',
|
||||
help='Specify the slide to use on the file specified with the --file option',
|
||||
default=None)
|
||||
parser.add_option(
|
||||
'--section',
|
||||
type='string',
|
||||
action='append',
|
||||
dest='section_strings',
|
||||
help='specify <sect-name>=<start-addr> or <sect-name>=<start-addr>-<end-addr>')
|
||||
try:
|
||||
(options, args) = parser.parse_args(command_args)
|
||||
except:
|
||||
return
|
||||
symbolicator = Symbolicator()
|
||||
images = list();
|
||||
images = list()
|
||||
if options.file:
|
||||
image = Image(options.file);
|
||||
image = Image(options.file)
|
||||
image.arch = options.arch
|
||||
# Add any sections that were specified with one or more --section options
|
||||
# Add any sections that were specified with one or more --section
|
||||
# options
|
||||
if options.section_strings:
|
||||
for section_str in options.section_strings:
|
||||
section = Section()
|
||||
if section.set_from_string (section_str):
|
||||
image.add_section (section)
|
||||
if section.set_from_string(section_str):
|
||||
image.add_section(section)
|
||||
else:
|
||||
sys.exit(1)
|
||||
if options.slide != None:
|
||||
if options.slide is not None:
|
||||
image.slide = options.slide
|
||||
symbolicator.images.append(image)
|
||||
|
||||
|
||||
target = symbolicator.create_target()
|
||||
if options.verbose:
|
||||
print symbolicator
|
||||
if target:
|
||||
for addr_str in args:
|
||||
addr = int(addr_str, 0)
|
||||
symbolicated_addrs = symbolicator.symbolicate(addr, options.verbose)
|
||||
symbolicated_addrs = symbolicator.symbolicate(
|
||||
addr, options.verbose)
|
||||
for symbolicated_addr in symbolicated_addrs:
|
||||
print symbolicated_addr
|
||||
print
|
||||
else:
|
||||
print 'error: no target for %s' % (symbolicator)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Create a new debugger instance
|
||||
lldb.debugger = lldb.SBDebugger.Create()
|
||||
Symbolicate (sys.argv[1:])
|
||||
Symbolicate(sys.argv[1:])
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
# Be sure to add the python path that points to the LLDB shared library.
|
||||
#
|
||||
# # To use this in the embedded python interpreter using "lldb" just
|
||||
# import it with the full path using the "command script import"
|
||||
# import it with the full path using the "command script import"
|
||||
# command
|
||||
# (lldb) command script import /path/to/cmdtemplate.py
|
||||
#----------------------------------------------------------------------
|
||||
@@ -16,7 +16,7 @@ import re
|
||||
import signal
|
||||
import sys
|
||||
|
||||
try:
|
||||
try:
|
||||
# Just try for LLDB in case PYTHONPATH is already correctly setup
|
||||
import lldb
|
||||
except ImportError:
|
||||
@@ -27,15 +27,20 @@ except ImportError:
|
||||
# On Darwin, try the currently selected Xcode directory
|
||||
xcode_dir = commands.getoutput("xcode-select --print-path")
|
||||
if xcode_dir:
|
||||
lldb_python_dirs.append(os.path.realpath(xcode_dir + '/../SharedFrameworks/LLDB.framework/Resources/Python'))
|
||||
lldb_python_dirs.append(xcode_dir + '/Library/PrivateFrameworks/LLDB.framework/Resources/Python')
|
||||
lldb_python_dirs.append('/System/Library/PrivateFrameworks/LLDB.framework/Resources/Python')
|
||||
lldb_python_dirs.append(
|
||||
os.path.realpath(
|
||||
xcode_dir +
|
||||
'/../SharedFrameworks/LLDB.framework/Resources/Python'))
|
||||
lldb_python_dirs.append(
|
||||
xcode_dir + '/Library/PrivateFrameworks/LLDB.framework/Resources/Python')
|
||||
lldb_python_dirs.append(
|
||||
'/System/Library/PrivateFrameworks/LLDB.framework/Resources/Python')
|
||||
success = False
|
||||
for lldb_python_dir in lldb_python_dirs:
|
||||
if os.path.exists(lldb_python_dir):
|
||||
if not (sys.path.__contains__(lldb_python_dir)):
|
||||
sys.path.append(lldb_python_dir)
|
||||
try:
|
||||
try:
|
||||
import lldb
|
||||
except ImportError:
|
||||
pass
|
||||
@@ -52,48 +57,111 @@ import optparse
|
||||
import shlex
|
||||
import time
|
||||
|
||||
|
||||
def regex_option_callback(option, opt_str, value, parser):
|
||||
if opt_str == "--std":
|
||||
value = '^std::'
|
||||
regex = re.compile(value)
|
||||
parser.values.skip_type_regexes.append (regex)
|
||||
parser.values.skip_type_regexes.append(regex)
|
||||
|
||||
|
||||
def create_types_options(for_lldb_command):
|
||||
if for_lldb_command:
|
||||
usage = "usage: %prog [options]"
|
||||
description='''This command will help check for padding in between
|
||||
description = '''This command will help check for padding in between
|
||||
base classes and members in structs and classes. It will summarize the types
|
||||
and how much padding was found. If no types are specified with the --types TYPENAME
|
||||
option, all structure and class types will be verified. If no modules are
|
||||
option, all structure and class types will be verified. If no modules are
|
||||
specified with the --module option, only the target's main executable will be
|
||||
searched.
|
||||
'''
|
||||
else:
|
||||
usage = "usage: %prog [options] EXEPATH [EXEPATH ...]"
|
||||
description='''This command will help check for padding in between
|
||||
description = '''This command will help check for padding in between
|
||||
base classes and members in structures and classes. It will summarize the types
|
||||
and how much padding was found. One or more paths to executable files must be
|
||||
specified and targets will be created with these modules. If no types are
|
||||
specified and targets will be created with these modules. If no types are
|
||||
specified with the --types TYPENAME option, all structure and class types will
|
||||
be verified in all specified modules.
|
||||
'''
|
||||
parser = optparse.OptionParser(description=description, prog='framestats',usage=usage)
|
||||
parser = optparse.OptionParser(
|
||||
description=description,
|
||||
prog='framestats',
|
||||
usage=usage)
|
||||
if not for_lldb_command:
|
||||
parser.add_option('-a', '--arch', type='string', dest='arch', help='The architecture to use when creating the debug target.', default=None)
|
||||
parser.add_option('-p', '--platform', type='string', metavar='platform', dest='platform', help='Specify the platform to use when creating the debug target. Valid values include "localhost", "darwin-kernel", "ios-simulator", "remote-freebsd", "remote-macosx", "remote-ios", "remote-linux".')
|
||||
parser.add_option('-m', '--module', action='append', type='string', metavar='MODULE', dest='modules', help='Specify one or more modules which will be used to verify the types.', default=[])
|
||||
parser.add_option('-d', '--debug', action='store_true', dest='debug', help='Pause 10 seconds to wait for a debugger to attach.', default=False)
|
||||
parser.add_option('-t', '--type', action='append', type='string', metavar='TYPENAME', dest='typenames', help='Specify one or more type names which should be verified. If no type names are specified, all class and struct types will be verified.', default=[])
|
||||
parser.add_option('-v', '--verbose', action='store_true', dest='verbose', help='Enable verbose logging and information.', default=False)
|
||||
parser.add_option('-s', '--skip-type-regex', action="callback", callback=regex_option_callback, type='string', metavar='REGEX', dest='skip_type_regexes', help='Regular expressions that, if they match the current member typename, will cause the type to no be recursively displayed.', default=[])
|
||||
parser.add_option('--std', action="callback", callback=regex_option_callback, metavar='REGEX', dest='skip_type_regexes', help="Don't' recurse into types in the std namespace.", default=[])
|
||||
parser.add_option(
|
||||
'-a',
|
||||
'--arch',
|
||||
type='string',
|
||||
dest='arch',
|
||||
help='The architecture to use when creating the debug target.',
|
||||
default=None)
|
||||
parser.add_option(
|
||||
'-p',
|
||||
'--platform',
|
||||
type='string',
|
||||
metavar='platform',
|
||||
dest='platform',
|
||||
help='Specify the platform to use when creating the debug target. Valid values include "localhost", "darwin-kernel", "ios-simulator", "remote-freebsd", "remote-macosx", "remote-ios", "remote-linux".')
|
||||
parser.add_option(
|
||||
'-m',
|
||||
'--module',
|
||||
action='append',
|
||||
type='string',
|
||||
metavar='MODULE',
|
||||
dest='modules',
|
||||
help='Specify one or more modules which will be used to verify the types.',
|
||||
default=[])
|
||||
parser.add_option(
|
||||
'-d',
|
||||
'--debug',
|
||||
action='store_true',
|
||||
dest='debug',
|
||||
help='Pause 10 seconds to wait for a debugger to attach.',
|
||||
default=False)
|
||||
parser.add_option(
|
||||
'-t',
|
||||
'--type',
|
||||
action='append',
|
||||
type='string',
|
||||
metavar='TYPENAME',
|
||||
dest='typenames',
|
||||
help='Specify one or more type names which should be verified. If no type names are specified, all class and struct types will be verified.',
|
||||
default=[])
|
||||
parser.add_option(
|
||||
'-v',
|
||||
'--verbose',
|
||||
action='store_true',
|
||||
dest='verbose',
|
||||
help='Enable verbose logging and information.',
|
||||
default=False)
|
||||
parser.add_option(
|
||||
'-s',
|
||||
'--skip-type-regex',
|
||||
action="callback",
|
||||
callback=regex_option_callback,
|
||||
type='string',
|
||||
metavar='REGEX',
|
||||
dest='skip_type_regexes',
|
||||
help='Regular expressions that, if they match the current member typename, will cause the type to no be recursively displayed.',
|
||||
default=[])
|
||||
parser.add_option(
|
||||
'--std',
|
||||
action="callback",
|
||||
callback=regex_option_callback,
|
||||
metavar='REGEX',
|
||||
dest='skip_type_regexes',
|
||||
help="Don't' recurse into types in the std namespace.",
|
||||
default=[])
|
||||
return parser
|
||||
|
||||
def verify_type (target, options, type):
|
||||
|
||||
def verify_type(target, options, type):
|
||||
print type
|
||||
typename = type.GetName()
|
||||
# print 'type: %s' % (typename)
|
||||
(end_offset, padding) = verify_type_recursive (target, options, type, None, 0, 0, 0)
|
||||
(end_offset, padding) = verify_type_recursive(
|
||||
target, options, type, None, 0, 0, 0)
|
||||
byte_size = type.GetByteSize()
|
||||
# if end_offset < byte_size:
|
||||
# last_member_padding = byte_size - end_offset
|
||||
@@ -105,7 +173,15 @@ def verify_type (target, options, type):
|
||||
print 'Padding percentage: %2.2f %%' % ((float(padding) / float(byte_size)) * 100.0)
|
||||
print
|
||||
|
||||
def verify_type_recursive (target, options, type, member_name, depth, base_offset, padding):
|
||||
|
||||
def verify_type_recursive(
|
||||
target,
|
||||
options,
|
||||
type,
|
||||
member_name,
|
||||
depth,
|
||||
base_offset,
|
||||
padding):
|
||||
prev_end_offset = base_offset
|
||||
typename = type.GetName()
|
||||
byte_size = type.GetByteSize()
|
||||
@@ -113,12 +189,12 @@ def verify_type_recursive (target, options, type, member_name, depth, base_offse
|
||||
print '%+4u <%3u> %s%s %s;' % (base_offset, byte_size, ' ' * depth, typename, member_name)
|
||||
else:
|
||||
print '%+4u {%3u} %s%s' % (base_offset, byte_size, ' ' * depth, typename)
|
||||
|
||||
|
||||
for type_regex in options.skip_type_regexes:
|
||||
match = type_regex.match (typename)
|
||||
match = type_regex.match(typename)
|
||||
if match:
|
||||
return (base_offset + byte_size, padding)
|
||||
|
||||
|
||||
members = type.members
|
||||
if members:
|
||||
for member_idx, member in enumerate(members):
|
||||
@@ -132,7 +208,8 @@ def verify_type_recursive (target, options, type, member_name, depth, base_offse
|
||||
member_is_class_or_struct = False
|
||||
if member_type_class == lldb.eTypeClassStruct or member_type_class == lldb.eTypeClassClass:
|
||||
member_is_class_or_struct = True
|
||||
if member_idx == 0 and member_offset == target.GetAddressByteSize() and type.IsPolymorphicClass():
|
||||
if member_idx == 0 and member_offset == target.GetAddressByteSize(
|
||||
) and type.IsPolymorphicClass():
|
||||
ptr_size = target.GetAddressByteSize()
|
||||
print '%+4u <%3u> %s__vtbl_ptr_type * _vptr;' % (prev_end_offset, ptr_size, ' ' * (depth + 1))
|
||||
prev_end_offset = ptr_size
|
||||
@@ -141,9 +218,16 @@ def verify_type_recursive (target, options, type, member_name, depth, base_offse
|
||||
member_padding = member_total_offset - prev_end_offset
|
||||
padding = padding + member_padding
|
||||
print '%+4u <%3u> %s<PADDING>' % (prev_end_offset, member_padding, ' ' * (depth + 1))
|
||||
|
||||
|
||||
if member_is_class_or_struct:
|
||||
(prev_end_offset, padding) = verify_type_recursive (target, options, member_canonical_type, member_name, depth + 1, member_total_offset, padding)
|
||||
(prev_end_offset,
|
||||
padding) = verify_type_recursive(target,
|
||||
options,
|
||||
member_canonical_type,
|
||||
member_name,
|
||||
depth + 1,
|
||||
member_total_offset,
|
||||
padding)
|
||||
else:
|
||||
prev_end_offset = member_total_offset + member_byte_size
|
||||
member_typename = member_type.GetName()
|
||||
@@ -151,7 +235,7 @@ def verify_type_recursive (target, options, type, member_name, depth, base_offse
|
||||
print '%+4u <%3u> %s%s:%u %s;' % (member_total_offset, member_byte_size, ' ' * (depth + 1), member_typename, member.GetBitfieldSizeInBits(), member_name)
|
||||
else:
|
||||
print '%+4u <%3u> %s%s %s;' % (member_total_offset, member_byte_size, ' ' * (depth + 1), member_typename, member_name)
|
||||
|
||||
|
||||
if prev_end_offset < byte_size:
|
||||
last_member_padding = byte_size - prev_end_offset
|
||||
print '%+4u <%3u> %s<PADDING>' % (prev_end_offset, last_member_padding, ' ' * (depth + 1))
|
||||
@@ -162,11 +246,12 @@ def verify_type_recursive (target, options, type, member_name, depth, base_offse
|
||||
print '%+4u <%3u> %s__vtbl_ptr_type * _vptr;' % (prev_end_offset, ptr_size, ' ' * (depth + 1))
|
||||
prev_end_offset = ptr_size
|
||||
prev_end_offset = base_offset + byte_size
|
||||
|
||||
|
||||
return (prev_end_offset, padding)
|
||||
|
||||
def check_padding_command (debugger, command, result, dict):
|
||||
# Use the Shell Lexer to properly parse up command options just like a
|
||||
|
||||
|
||||
def check_padding_command(debugger, command, result, dict):
|
||||
# Use the Shell Lexer to properly parse up command options just like a
|
||||
# shell would
|
||||
command_args = shlex.split(command)
|
||||
parser = create_types_options(True)
|
||||
@@ -175,30 +260,33 @@ def check_padding_command (debugger, command, result, dict):
|
||||
except:
|
||||
# if you don't handle exceptions, passing an incorrect argument to the OptionParser will cause LLDB to exit
|
||||
# (courtesy of OptParse dealing with argument errors by throwing SystemExit)
|
||||
result.SetStatus (lldb.eReturnStatusFailed)
|
||||
return "option parsing failed" # returning a string is the same as returning an error whose description is the string
|
||||
result.SetStatus(lldb.eReturnStatusFailed)
|
||||
# returning a string is the same as returning an error whose
|
||||
# description is the string
|
||||
return "option parsing failed"
|
||||
verify_types(debugger.GetSelectedTarget(), options)
|
||||
|
||||
|
||||
@lldb.command("parse_all_struct_class_types")
|
||||
def parse_all_struct_class_types (debugger, command, result, dict):
|
||||
def parse_all_struct_class_types(debugger, command, result, dict):
|
||||
command_args = shlex.split(command)
|
||||
for f in command_args:
|
||||
error = lldb.SBError()
|
||||
target = debugger.CreateTarget (f, None, None, False, error)
|
||||
target = debugger.CreateTarget(f, None, None, False, error)
|
||||
module = target.GetModuleAtIndex(0)
|
||||
print "Parsing all types in '%s'" % (module)
|
||||
types = module.GetTypes(lldb.eTypeClassClass | lldb.eTypeClassStruct)
|
||||
for t in types:
|
||||
print t
|
||||
print ""
|
||||
|
||||
|
||||
def verify_types (target, options):
|
||||
|
||||
|
||||
def verify_types(target, options):
|
||||
|
||||
if not target:
|
||||
print 'error: invalid target'
|
||||
return
|
||||
|
||||
|
||||
modules = list()
|
||||
if len(options.modules) == 0:
|
||||
# Append just the main executable if nothing was specified
|
||||
@@ -210,7 +298,7 @@ def verify_types (target, options):
|
||||
module = lldb.target.module[module_name]
|
||||
if module:
|
||||
modules.append(module)
|
||||
|
||||
|
||||
if modules:
|
||||
for module in modules:
|
||||
print 'module: %s' % (module.file)
|
||||
@@ -220,46 +308,49 @@ def verify_types (target, options):
|
||||
if types.GetSize():
|
||||
print 'Found %u types matching "%s" in "%s"' % (len(types), typename, module.file)
|
||||
for type in types:
|
||||
verify_type (target, options, type)
|
||||
verify_type(target, options, type)
|
||||
else:
|
||||
print 'error: no type matches "%s" in "%s"' % (typename, module.file)
|
||||
else:
|
||||
types = module.GetTypes(lldb.eTypeClassClass | lldb.eTypeClassStruct)
|
||||
types = module.GetTypes(
|
||||
lldb.eTypeClassClass | lldb.eTypeClassStruct)
|
||||
print 'Found %u types in "%s"' % (len(types), module.file)
|
||||
for type in types:
|
||||
verify_type (target, options, type)
|
||||
verify_type(target, options, type)
|
||||
else:
|
||||
print 'error: no modules'
|
||||
|
||||
if __name__ == '__main__':
|
||||
debugger = lldb.SBDebugger.Create()
|
||||
parser = create_types_options(False)
|
||||
|
||||
|
||||
# try:
|
||||
(options, args) = parser.parse_args(sys.argv[1:])
|
||||
# except:
|
||||
# print "error: option parsing failed"
|
||||
# print "error: option parsing failed"
|
||||
# sys.exit(1)
|
||||
|
||||
|
||||
if options.debug:
|
||||
print "Waiting for debugger to attach to process %d" % os.getpid()
|
||||
os.kill(os.getpid(), signal.SIGSTOP)
|
||||
|
||||
|
||||
for path in args:
|
||||
# in a command - the lldb.* convenience variables are not to be used
|
||||
# and their values (if any) are undefined
|
||||
# this is the best practice to access those objects from within a command
|
||||
# in a command - the lldb.* convenience variables are not to be used
|
||||
# and their values (if any) are undefined
|
||||
# this is the best practice to access those objects from within a
|
||||
# command
|
||||
error = lldb.SBError()
|
||||
target = debugger.CreateTarget (path,
|
||||
options.arch,
|
||||
options.platform,
|
||||
True,
|
||||
error)
|
||||
target = debugger.CreateTarget(path,
|
||||
options.arch,
|
||||
options.platform,
|
||||
True,
|
||||
error)
|
||||
if error.Fail():
|
||||
print error.GetCString()
|
||||
continue
|
||||
verify_types (target, options)
|
||||
|
||||
verify_types(target, options)
|
||||
|
||||
elif getattr(lldb, 'debugger', None):
|
||||
lldb.debugger.HandleCommand('command script add -f types.check_padding_command check_padding')
|
||||
print '"check_padding" command installed, use the "--help" option for detailed help'
|
||||
lldb.debugger.HandleCommand(
|
||||
'command script add -f types.check_padding_command check_padding')
|
||||
print '"check_padding" command installed, use the "--help" option for detailed help'
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user