summaryrefslogtreecommitdiff
path: root/examples/python
diff options
context:
space:
mode:
Diffstat (limited to 'examples/python')
-rw-r--r--examples/python/cmdtemplate.py180
-rwxr-xr-xexamples/python/crashlog.py13
-rw-r--r--examples/python/lldb_module_utils.py249
-rw-r--r--examples/python/step_and_print.py24
4 files changed, 307 insertions, 159 deletions
diff --git a/examples/python/cmdtemplate.py b/examples/python/cmdtemplate.py
index dfe3e6fa52b96..4d506b91aaf87 100644
--- a/examples/python/cmdtemplate.py
+++ b/examples/python/cmdtemplate.py
@@ -14,99 +14,109 @@ import commands
import optparse
import shlex
+class FrameStatCommand:
+ def create_options(self):
-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
+ usage = "usage: %prog [options]"
+ 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)
- return parser
-
-
-def the_framestats_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_framestats_options()
- try:
- (options, args) = parser.parse_args(command_args)
- 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")
- 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
- target = debugger.GetSelectedTarget()
- process = target.GetProcess()
- thread = process.GetSelectedThread()
- frame = thread.GetSelectedFrame()
- 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_count = variables_list.GetSize()
- if variables_count == 0:
- print >> result, "no variables here"
- return
- total_size = 0
- 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)
- # not returning anything is akin to returning success
+
+ # Pass add_help_option = False, since this keeps the command in line with lldb commands,
+ # and we wire up "help command" to work by providing the long & short help methods below.
+ self.parser = optparse.OptionParser(
+ description = description,
+ prog = 'framestats',
+ usage = usage,
+ add_help_option = False)
+
+ self.parser.add_option(
+ '-i',
+ '--in-scope',
+ action = 'store_true',
+ dest = 'inscope',
+ help = 'in_scope_only = True',
+ default = True)
+
+ self.parser.add_option(
+ '-a',
+ '--arguments',
+ action = 'store_true',
+ dest = 'arguments',
+ help = 'arguments = True',
+ default = True)
+
+ self.parser.add_option(
+ '-l',
+ '--locals',
+ action = 'store_true',
+ dest = 'locals',
+ help = 'locals = True',
+ default = True)
+
+ self.parser.add_option(
+ '-s',
+ '--statics',
+ action = 'store_true',
+ dest = 'statics',
+ help = 'statics = True',
+ default = True)
+
+ def get_short_help(self):
+ return "Example command for use in debugging"
+
+ def get_long_help(self):
+ return self.help_string
+
+ def __init__(self, debugger, unused):
+ self.create_options()
+ self.help_string = self.parser.format_help()
+
+ def __call__(self, debugger, command, exe_ctx, result):
+ # Use the Shell Lexer to properly parse up command options just like a
+ # shell would
+ command_args = shlex.split(command)
+
+ try:
+ (options, args) = self.parser.parse_args(command_args)
+ 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")
+ return
+
+ # Always get program state from the SBExecutionContext passed in as exe_ctx
+ frame = exe_ctx.GetFrame()
+ if not frame.IsValid():
+ result.SetError("invalid frame")
+ return
+
+ 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):
+ 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)
+ # 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
- # 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')
- print 'The "framestats" command has been installed, type "help framestats" or "framestats --help" for detailed help.'
+ 'command script add -c cmdtemplate.FrameStatCommand framestats')
+ print 'The "framestats" command has been installed, type "help framestats" for detailed help.'
diff --git a/examples/python/crashlog.py b/examples/python/crashlog.py
index 7270f60f4373b..227fce1140524 100755
--- a/examples/python/crashlog.py
+++ b/examples/python/crashlog.py
@@ -680,7 +680,7 @@ def interactive_crashlogs(options, args):
interpreter.cmdloop()
-def save_crashlog(debugger, command, result, dict):
+def save_crashlog(debugger, command, exe_ctx, result, dict):
usage = "usage: %prog [options] <output-path>"
description = '''Export the state of current target into a crashlog file'''
parser = optparse.OptionParser(
@@ -709,11 +709,12 @@ def save_crashlog(debugger, command, result, dict):
"error: failed to open file '%s' for writing...",
args[0])
return
- target = debugger.GetSelectedTarget()
+ target = exe_ctx.target
if target:
identifier = target.executable.basename
- if lldb.process:
- pid = lldb.process.id
+ process = exe_ctx.process
+ if process:
+ pid = process.id
if pid != lldb.LLDB_INVALID_PROCESS_ID:
out_file.write(
'Process: %s [%u]\n' %
@@ -726,8 +727,8 @@ def save_crashlog(debugger, command, result, dict):
'OS Version: Mac OS X %s (%s)\n' %
(platform.mac_ver()[0], commands.getoutput('sysctl -n kern.osversion')))
out_file.write('Report Version: 9\n')
- for thread_idx in range(lldb.process.num_threads):
- thread = lldb.process.thread[thread_idx]
+ for thread_idx in range(process.num_threads):
+ thread = process.thread[thread_idx]
out_file.write('\nThread %u:\n' % (thread_idx))
for (frame_idx, frame) in enumerate(thread.frames):
frame_pc = frame.pc
diff --git a/examples/python/lldb_module_utils.py b/examples/python/lldb_module_utils.py
index eb00a489ce014..006f232681f83 100644
--- a/examples/python/lldb_module_utils.py
+++ b/examples/python/lldb_module_utils.py
@@ -7,72 +7,185 @@ import string
import sys
-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)
- 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()
- try:
- (options, args) = parser.parse_args(command_args)
- except:
- return
- if command_args:
- target = debugger.GetSelectedTarget()
- 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)
- if module:
- 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 options.verbose:
- if start_file_addr != end_file_addr:
- 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))
- else:
- result.PutCString(
- '%#x: %s' %
- (start_file_addr, line_entry))
+class DumpLineTables:
+ command_name = "dump-line-tables"
+ short_decription = "Dumps full paths to compile unit files and optionally all line table files."
+ 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.'
+ usage = "usage: %prog [options] MODULE1 [MODULE2 ...]"
+ def create_options(self):
+ self.parser = optparse.OptionParser(
+ description=self.description,
+ prog=self.command_name,
+ usage=self.usage)
+
+ self.parser.add_option(
+ '-v',
+ '--verbose',
+ action='store_true',
+ dest='verbose',
+ help='Display verbose output.',
+ default=False)
+
+ def get_short_help(self):
+ return self.short_decription
+
+ def get_long_help(self):
+ return self.help_string
+
+ def __init__(self, debugger, unused):
+ self.create_options()
+ self.help_string = self.parser.format_help()
+
+ def __call__(self, debugger, command, exe_ctx, result):
+ # Use the Shell Lexer to properly parse up command options just like a
+ # shell would
+ command_args = shlex.split(command)
+
+ try:
+ (options, args) = self.parser.parse_args(command_args)
+ 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")
+ return
+
+ # Always get program state from the SBExecutionContext passed in as exe_ctx
+ target = exe_ctx.GetTarget()
+ if not target.IsValid():
+ result.SetError("invalid target")
+ return
+
+ for module_path in args:
+ module = target.module[module_path]
+ if not module:
+ result.SetError('no module found that matches "%s".' % (module_path))
+ return
+ num_cus = module.GetNumCompileUnits()
+ print >>result, 'Module: "%s"' % (module.file.fullpath),
+ if num_cus == 0:
+ print >>result, 'no debug info.'
+ continue
+ print >>result, 'has %u compile units:' % (num_cus)
+ for cu_idx in range(num_cus):
+ cu = module.GetCompileUnitAtIndex(cu_idx)
+ print >>result, ' Compile Unit: %s' % (cu.file.fullpath)
+ 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 options.verbose:
+ if start_file_addr != end_file_addr:
+ result.PutCString(
+ ' [%#x - %#x): %s' %
+ (start_file_addr, end_file_addr, line_entry))
+ else:
if start_file_addr == end_file_addr:
- result.Printf("\n")
- else:
- result.PutCString("no module for '%s'" % module)
- else:
- result.PutCString("error: invalid target")
-
-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'
+ result.PutCString(' %#x: END' %
+ (start_file_addr))
+ else:
+ result.PutCString(
+ ' %#x: %s' %
+ (start_file_addr, line_entry))
+ if start_file_addr == end_file_addr:
+ result.PutCString("\n")
+
+
+class DumpFiles:
+ command_name = "dump-files"
+ short_description = "Dumps full paths to compile unit files and optionally all line table files."
+ usage = "usage: %prog [options] MODULE1 [MODULE2 ...]"
+ description = '''This class adds a dump-files command to the LLDB interpreter.
+
+This command will dump all compile unit file paths found for each source file
+for the binaries specified as arguments in the current target. Specify the
+--support-files or -s option to see all file paths that a compile unit uses in
+its lines tables. This is handy for troubleshooting why breakpoints aren't
+working in IDEs that specify full paths to source files when setting file and
+line breakpoints. Sometimes symlinks cause the debug info to contain the symlink
+path and an IDE will resolve the path to the actual file and use the resolved
+path when setting breakpoints.
+'''
+ def create_options(self):
+ # Pass add_help_option = False, since this keeps the command in line with lldb commands,
+ # and we wire up "help command" to work by providing the long & short help methods below.
+ self.parser = optparse.OptionParser(
+ description = self.description,
+ prog = self.command_name,
+ usage = self.usage,
+ add_help_option = False)
+
+ self.parser.add_option(
+ '-s',
+ '--support-files',
+ action = 'store_true',
+ dest = 'support_files',
+ help = 'Dumps full paths to all files used in a compile unit.',
+ default = False)
+
+ def get_short_help(self):
+ return self.short_description
+
+ def get_long_help(self):
+ return self.help_string
+
+ def __init__(self, debugger, unused):
+ self.create_options()
+ self.help_string = self.parser.format_help()
+
+ def __call__(self, debugger, command, exe_ctx, result):
+ # Use the Shell Lexer to properly parse up command options just like a
+ # shell would
+ command_args = shlex.split(command)
+
+ try:
+ (options, args) = self.parser.parse_args(command_args)
+ 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")
+ return
+
+ # Always get program state from the SBExecutionContext passed in as exe_ctx
+ target = exe_ctx.GetTarget()
+ if not target.IsValid():
+ result.SetError("invalid target")
+ return
+
+ if len(args) == 0:
+ result.SetError("one or more executable paths must be specified")
+ return
+
+ for module_path in args:
+ module = target.module[module_path]
+ if not module:
+ result.SetError('no module found that matches "%s".' % (module_path))
+ return
+ num_cus = module.GetNumCompileUnits()
+ print >>result, 'Module: "%s"' % (module.file.fullpath),
+ if num_cus == 0:
+ print >>result, 'no debug info.'
+ continue
+ print >>result, 'has %u compile units:' % (num_cus)
+ for i in range(num_cus):
+ cu = module.GetCompileUnitAtIndex(i)
+ print >>result, ' Compile Unit: %s' % (cu.file.fullpath)
+ if options.support_files:
+ num_support_files = cu.GetNumSupportFiles()
+ for j in range(num_support_files):
+ path = cu.GetSupportFileAtIndex(j).fullpath
+ print >>result, ' file[%u]: %s' % (j, path)
+
+
+def __lldb_init_module(debugger, dict):
+ # This initializer is being run from LLDB in the embedded command interpreter
+
+ # Add any commands contained in this module to LLDB
+ debugger.HandleCommand(
+ 'command script add -c %s.DumpLineTables %s' % (__name__,
+ DumpLineTables.command_name))
+ debugger.HandleCommand(
+ 'command script add -c %s.DumpFiles %s' % (__name__, DumpFiles.command_name))
+ print 'The "%s" and "%s" commands have been installed.' % (DumpLineTables.command_name,
+ DumpFiles.command_name)
diff --git a/examples/python/step_and_print.py b/examples/python/step_and_print.py
new file mode 100644
index 0000000000000..41364ef97ba84
--- /dev/null
+++ b/examples/python/step_and_print.py
@@ -0,0 +1,24 @@
+""" Does a step-over then prints the local variables or only the ones passed in """
+import lldb
+
+class StepAndPrint:
+ def __init__(self, debugger, unused):
+ return
+
+ def __call__(self, debugger, command, exe_ctx, result):
+ # Set the command to synchronous so the step will complete
+ # before we try to run the frame variable.
+ old_async = debugger.GetAsync()
+ debugger.SetAsync(False)
+
+ debugger.HandleCommand("thread step-over")
+ print("---------- Values: -------------------\n")
+ debugger.HandleCommand("frame variable %s"%(command))
+
+ debugger.SetAsync(old_async)
+
+ def get_short_help(self):
+ return "Does a step-over then runs frame variable passing the command args to it\n"
+
+def __lldb_init_module(debugger, unused):
+ debugger.HandleCommand("command script add -c step_and_print.StepAndPrint sap")