diff options
Diffstat (limited to 'lldb/examples/python')
| -rw-r--r-- | lldb/examples/python/cmdtemplate.py | 50 | ||||
| -rwxr-xr-x | lldb/examples/python/crashlog.py | 473 | ||||
| -rwxr-xr-x | lldb/examples/python/delta.py | 115 | ||||
| -rwxr-xr-x | lldb/examples/python/disasm-stress-test.py | 168 | ||||
| -rwxr-xr-x | lldb/examples/python/disasm.py | 119 | ||||
| -rwxr-xr-x | lldb/examples/python/gdbremote.py | 197 | ||||
| -rwxr-xr-x | lldb/examples/python/sbvalue.py | 255 | ||||
| -rwxr-xr-x | lldb/examples/python/symbolication.py | 524 |
8 files changed, 0 insertions, 1901 deletions
diff --git a/lldb/examples/python/cmdtemplate.py b/lldb/examples/python/cmdtemplate.py deleted file mode 100644 index 33dee94fcfe6..000000000000 --- a/lldb/examples/python/cmdtemplate.py +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/python - -#---------------------------------------------------------------------- -# 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" -# command -# (lldb) command script import /path/to/cmdtemplate.py -# -# For the shells csh, tcsh: -# ( setenv PYTHONPATH /path/to/LLDB.framework/Resources/Python ; ./cmdtemplate.py ) -# -# For the shells sh, bash: -# PYTHONPATH=/path/to/LLDB.framework/Resources/Python ./cmdtemplate.py -#---------------------------------------------------------------------- - -import lldb -import commands -import optparse -import shlex - -def ls(debugger, command, result, dict): - command_args = shlex.split(command) - usage = "usage: %prog [options] <PATH> [PATH ...]" - description='''This command lets you run the /bin/ls command from within lldb as a quick and easy example.''' - 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 - - for arg in args: - if options.verbose: - result.PutCString(commands.getoutput('/bin/ls "%s"' % arg)) - else: - result.PutCString(commands.getoutput('/bin/ls -lAF "%s"' % arg)) - -if __name__ == '__main__': - # This script is being run from the command line, create a debugger in case we are - # going to use any debugger functions in our function. - lldb.debugger = lldb.SBDebugger.Create() - ls (sys.argv) - -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 -f cmdtemplate.ls ls') - print '"ls" command installed, type "ls --help" for detailed help' diff --git a/lldb/examples/python/crashlog.py b/lldb/examples/python/crashlog.py deleted file mode 100755 index 725ea2e5fe38..000000000000 --- a/lldb/examples/python/crashlog.py +++ /dev/null @@ -1,473 +0,0 @@ -#!/usr/bin/python - -#---------------------------------------------------------------------- -# Be sure to add the python path that points to the LLDB shared library. -# -# To use this in the embedded python interpreter using "lldb": -# -# cd /path/containing/crashlog.py -# lldb -# (lldb) script import crashlog -# "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 -# 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. -# -# On MacOSX csh, tcsh: -# ( setenv PYTHONPATH /path/to/LLDB.framework/Resources/Python ; ./crashlog.py ~/Library/Logs/DiagnosticReports/a.crash ) -# -# On MacOSX sh, bash: -# PYTHONPATH=/path/to/LLDB.framework/Resources/Python ./crashlog.py ~/Library/Logs/DiagnosticReports/a.crash -#---------------------------------------------------------------------- - -import lldb -import commands -import optparse -import os -import plistlib -import pprint # pp = pprint.PrettyPrinter(indent=4); pp.pprint(command_args) -import re -import shlex -import sys -import time -import uuid -import symbolication - -PARSE_MODE_NORMAL = 0 -PARSE_MODE_THREAD = 1 -PARSE_MODE_IMAGES = 2 -PARSE_MODE_THREGS = 3 -PARSE_MODE_SYSTEM = 4 - -class CrashLog(symbolication.Symbolicator): - """Class that does parses darwin crash logs""" - thread_state_regex = re.compile('^Thread ([0-9]+) crashed with') - thread_regex = re.compile('^Thread ([0-9]+)([^:]*):(.*)') - frame_regex = re.compile('^([0-9]+) +([^ ]+) *\t(0x[0-9a-fA-F]+) +(.*)') - image_regex_uuid = re.compile('(0x[0-9a-fA-F]+)[- ]+(0x[0-9a-fA-F]+) +[+]?([^ ]+) +([^<]+)<([-0-9a-fA-F]+)> (.*)'); - image_regex_no_uuid = re.compile('(0x[0-9a-fA-F]+)[- ]+(0x[0-9a-fA-F]+) +[+]?([^ ]+) +([^/]+)/(.*)'); - empty_line_regex = re.compile('^$') - - class Thread: - """Class that represents a thread in a darwin crash log""" - def __init__(self, index): - self.index = index - self.frames = list() - self.registers = dict() - self.reason = None - self.queue = None - - def dump(self, prefix): - print "%sThread[%u] %s" % (prefix, self.index, self.reason) - if self.frames: - print "%s Frames:" % (prefix) - for frame in self.frames: - frame.dump(prefix + ' ') - if self.registers: - print "%s Registers:" % (prefix) - for reg in self.registers.keys(): - print "%s %-5s = %#16.16x" % (prefix, reg, self.registers[reg]) - - def did_crash(self): - return self.reason != None - - def __str__(self): - s = "Thread[%u]" % self.index - if self.reason: - s += ' %s' % self.reason - return s - - - class Frame: - """Class that represents a stack frame in a thread in a darwin crash log""" - def __init__(self, index, pc, description): - self.pc = pc - self.description = description - self.index = index - - def __str__(self): - if self.description: - return "[%3u] 0x%16.16x %s" % (self.index, self.pc, self.description) - else: - return "[%3u] 0x%16.16x" % (self.index, self.pc) - - class DarwinImage(symbolication.Image): - """Class that represents a binary images in a darwin crash log""" - dsymForUUIDBinary = os.path.expanduser('~rc/bin/dsymForUUID') - if not os.path.exists(dsymForUUIDBinary): - dsymForUUIDBinary = commands.getoutput('which dsymForUUID') - - dwarfdump_uuid_regex = re.compile('UUID: ([-0-9a-fA-F]+) \(([^\(]+)\) .*') - - def __init__(self, text_addr_lo, text_addr_hi, identifier, version, uuid, path): - symbolication.Image.__init__(self, path, uuid); - self.add_section (symbolication.Section(text_addr_lo, text_addr_hi, "__TEXT")) - self.identifier = identifier - self.version = version - - def locate_module_and_debug_symbols(self): - if self.resolved_path: - # Don't load a module twice... - return 0 - print 'Locating %s %s...' % (self.uuid, self.path), - if os.path.exists(self.dsymForUUIDBinary): - dsym_for_uuid_command = '%s %s' % (self.dsymForUUIDBinary, self.uuid) - s = commands.getoutput(dsym_for_uuid_command) - if s: - plist_root = plistlib.readPlistFromString (s) - if plist_root: - plist = plist_root[self.uuid] - if plist: - if 'DBGArchitecture' in plist: - self.arch = plist['DBGArchitecture'] - if 'DBGDSYMPath' in plist: - self.symfile = os.path.realpath(plist['DBGDSYMPath']) - if 'DBGSymbolRichExecutable' in plist: - self.resolved_path = os.path.expanduser (plist['DBGSymbolRichExecutable']) - if not self.resolved_path and os.path.exists(self.path): - dwarfdump_cmd_output = commands.getoutput('dwarfdump --uuid "%s"' % self.path) - self_uuid = uuid.UUID(self.uuid) - for line in dwarfdump_cmd_output.splitlines(): - match = self.dwarfdump_uuid_regex.search (line) - if match: - dwarf_uuid_str = match.group(1) - dwarf_uuid = uuid.UUID(dwarf_uuid_str) - if self_uuid == dwarf_uuid: - self.resolved_path = self.path - self.arch = match.group(2) - break; - if not self.resolved_path: - print "error: file %s '%s' doesn't match the UUID in the installed file" % (self.uuid, self.path) - return 0 - if (self.resolved_path and os.path.exists(self.resolved_path)) or (self.path and os.path.exists(self.path)): - print 'ok' - if self.path != self.resolved_path: - print ' exe = "%s"' % self.resolved_path - if self.symfile: - print ' dsym = "%s"' % self.symfile - return 1 - else: - return 0 - - - - def __init__(self, path): - """CrashLog constructor that take a path to a darwin crash log file""" - symbolication.Symbolicator.__init__(self); - self.path = os.path.expanduser(path); - self.info_lines = list() - self.system_profile = list() - self.threads = list() - self.idents = list() # A list of the required identifiers for doing all stack backtraces - self.crashed_thread_idx = -1 - self.version = -1 - self.error = None - # With possible initial component of ~ or ~user replaced by that user's home directory. - try: - f = open(self.path) - except IOError: - self.error = 'error: cannot open "%s"' % self.path - return - - self.file_lines = f.read().splitlines() - parse_mode = PARSE_MODE_NORMAL - thread = None - for line in self.file_lines: - # print line - line_len = len(line) - if line_len == 0: - if thread: - if parse_mode == PARSE_MODE_THREAD: - if thread.index == self.crashed_thread_idx: - thread.reason = '' - if self.thread_exception: - thread.reason += self.thread_exception - if self.thread_exception_data: - thread.reason += " (%s)" % self.thread_exception_data - self.threads.append(thread) - thread = None - else: - # only append an extra empty line if the previous line - # in the info_lines wasn't empty - if len(self.info_lines) > 0 and len(self.info_lines[-1]): - self.info_lines.append(line) - parse_mode = PARSE_MODE_NORMAL - # print 'PARSE_MODE_NORMAL' - elif parse_mode == PARSE_MODE_NORMAL: - if line.startswith ('Process:'): - (self.process_name, pid_with_brackets) = line[8:].strip().split() - self.process_id = pid_with_brackets.strip('[]') - elif line.startswith ('Path:'): - self.process_path = line[5:].strip() - elif line.startswith ('Identifier:'): - self.process_identifier = line[11:].strip() - elif line.startswith ('Version:'): - (self.process_version, compatability_version) = line[8:].strip().split() - self.process_compatability_version = compatability_version.strip('()') - elif line.startswith ('Parent Process:'): - (self.parent_process_name, pid_with_brackets) = line[15:].strip().split() - self.parent_process_id = pid_with_brackets.strip('[]') - elif line.startswith ('Exception Type:'): - self.thread_exception = line[15:].strip() - continue - elif line.startswith ('Exception Codes:'): - self.thread_exception_data = line[16:].strip() - continue - elif line.startswith ('Crashed Thread:'): - self.crashed_thread_idx = int(line[15:].strip().split()[0]) - continue - elif line.startswith ('Report Version:'): - self.version = int(line[15:].strip()) - continue - elif line.startswith ('System Profile:'): - parse_mode = PARSE_MODE_SYSTEM - continue - elif (line.startswith ('Interval Since Last Report:') or - line.startswith ('Crashes Since Last Report:') or - line.startswith ('Per-App Interval Since Last Report:') or - line.startswith ('Per-App Crashes Since Last Report:') or - line.startswith ('Sleep/Wake UUID:') or - line.startswith ('Anonymous UUID:')): - # ignore these - continue - elif line.startswith ('Thread'): - thread_state_match = self.thread_state_regex.search (line) - if thread_state_match: - thread_state_match = self.thread_regex.search (line) - thread_idx = int(thread_state_match.group(1)) - parse_mode = PARSE_MODE_THREGS - thread = self.threads[thread_idx] - else: - thread_match = self.thread_regex.search (line) - if thread_match: - # print 'PARSE_MODE_THREAD' - parse_mode = PARSE_MODE_THREAD - thread_idx = int(thread_match.group(1)) - thread = CrashLog.Thread(thread_idx) - continue - elif line.startswith ('Binary Images:'): - parse_mode = PARSE_MODE_IMAGES - continue - self.info_lines.append(line.strip()) - elif parse_mode == PARSE_MODE_THREAD: - frame_match = self.frame_regex.search(line) - if frame_match: - ident = frame_match.group(2) - if not ident in self.idents: - self.idents.append(ident) - thread.frames.append (CrashLog.Frame(int(frame_match.group(1)), int(frame_match.group(3), 0), frame_match.group(4))) - else: - print 'error: frame regex failed for line: "%s"' % line - elif parse_mode == PARSE_MODE_IMAGES: - image_match = self.image_regex_uuid.search (line) - if image_match: - image = CrashLog.DarwinImage (int(image_match.group(1),0), - int(image_match.group(2),0), - image_match.group(3).strip(), - image_match.group(4).strip(), - image_match.group(5), - image_match.group(6)) - self.images.append (image) - else: - image_match = self.image_regex_no_uuid.search (line) - if image_match: - image = CrashLog.DarwinImage (int(image_match.group(1),0), - int(image_match.group(2),0), - image_match.group(3).strip(), - image_match.group(4).strip(), - None, - image_match.group(5)) - self.images.append (image) - else: - print "error: image regex failed for: %s" % line - - elif parse_mode == PARSE_MODE_THREGS: - stripped_line = line.strip() - reg_values = stripped_line.split(' ') - for reg_value in reg_values: - (reg, value) = reg_value.split(': ') - thread.registers[reg.strip()] = int(value, 0) - elif parse_mode == PARSE_MODE_SYSTEM: - self.system_profile.append(line) - f.close() - - def dump(self): - print "Crash Log File: %s" % (self.path) - print "\nThreads:" - for thread in self.threads: - thread.dump(' ') - print "\nImages:" - for image in self.images: - image.dump(' ') - - def find_image_with_identifier(self, identifier): - for image in self.images: - if image.identifier == identifier: - return image - return None - - def create_target(self): - #print 'crashlog.create_target()...' - target = symbolication.Symbolicator.create_target(self) - if target: - return target - # We weren't able to open the main executable as, but we can still symbolicate - print 'crashlog.create_target()...2' - if self.idents: - for ident in self.idents: - image = self.find_image_with_identifier (ident) - if image: - target = image.create_target () - if target: - return target # success - print 'crashlog.create_target()...3' - for image in self.images: - target = image.create_target () - if target: - return target # success - print 'crashlog.create_target()...4' - print 'error: unable to locate any executables from the crash log' - return None - - -def usage(): - print "Usage: lldb-symbolicate.py [-n name] executable-image" - sys.exit(0) - -def Symbolicate(debugger, command, result, dict): - try: - SymbolicateCrashLog (shlex.split(command)) - except: - result.PutCString ("error: python exception %s" % sys.exc_info()[0]) - -def SymbolicateCrashLog(command_args): - usage = "usage: %prog [options] <FILE> [FILE ...]" - description='''Symbolicate one or more darwin crash log files to provide source file and line information, -inlined stack frames back to the concrete functions, and disassemble the location of the crash -for the first frame of the crashed thread. -If this script is imported into the LLDB command interpreter, a "crashlog" command will be added to the interpreter -for use at the LLDB command line. After a crash log has been parsed and symbolicated, a target will have been -created that has all of the shared libraries loaded at the load addresses found in the crash log file. This allows -you to explore the program as if it were stopped at the locations described in the crash log and functions can -be disassembled and lookups can be performed using the addresses found in the crash log.''' - parser = optparse.OptionParser(description=description, prog='crashlog.py',usage=usage) - parser.add_option('--platform', type='string', metavar='platform', dest='platform', help='specify one platform by name') - parser.add_option('-v', '--verbose', action='store_true', dest='verbose', help='display verbose debug info', default=False) - parser.add_option('--no-images', action='store_false', dest='show_images', help='don\'t show images in stack frames', default=True) - parser.add_option('-a', '--load-all', action='store_true', dest='load_all_images', help='load all executable images, not just the images found in the crashed stack frames', default=False) - parser.add_option('--image-list', action='store_true', dest='dump_image_list', help='show image list', default=False) - parser.add_option('-g', '--debug-delay', type='int', dest='debug_delay', metavar='NSEC', help='pause for NSEC seconds for debugger', default=0) - parser.add_option('-c', '--crashed-only', action='store_true', dest='crashed_only', help='only symbolicate the crashed thread', default=False) - parser.add_option('-d', '--disasm-depth', type='int', dest='disassemble_depth', help='set the depth in stack frames that should be disassembled (default is 1)', default=1) - parser.add_option('-D', '--disasm-all', action='store_true', dest='disassemble_all_threads', help='enabled disassembly of frames on all threads (not just the crashed thread)', default=False) - parser.add_option('-B', '--disasm-before', type='int', dest='disassemble_before', help='the number of instructions to disassemble before the frame PC', default=4) - parser.add_option('-A', '--disasm-after', type='int', dest='disassemble_after', help='the number of instructions to disassemble after the frame PC', default=4) - loaded_addresses = False - try: - (options, args) = parser.parse_args(command_args) - except: - return - - if options.verbose: - print 'command_args = %s' % command_args - print 'options', options - print 'args', args - - if options.debug_delay > 0: - print "Waiting %u seconds for debugger to attach..." % options.debug_delay - time.sleep(options.debug_delay) - error = lldb.SBError() - if args: - for crash_log_file in args: - crash_log = CrashLog(crash_log_file) - - #pp = pprint.PrettyPrinter(indent=4); pp.pprint(args) - if crash_log.error: - print crash_log.error - return - if options.verbose: - crash_log.dump() - if not crash_log.images: - print 'error: no images in crash log' - return - - target = crash_log.create_target () - if not target: - return - exe_module = target.GetModuleAtIndex(0) - images_to_load = list() - loaded_images = list() - if options.load_all_images: - # --load-all option was specified, load everything up - for image in crash_log.images: - images_to_load.append(image) - else: - # Only load the images found in stack frames for the crashed threads - for ident in crash_log.idents: - images = crash_log.find_images_with_identifier (ident) - if images: - for image in images: - images_to_load.append(image) - else: - print 'error: can\'t find image for identifier "%s"' % ident - - for image in images_to_load: - if image in loaded_images: - print "warning: skipping %s loaded at %#16.16x duplicate entry (probably commpage)" % (image.path, image.text_addr_lo) - else: - err = image.add_module (target) - if err: - print err - else: - print 'loaded %s' % image - loaded_images.append(image) - - for thread in crash_log.threads: - this_thread_crashed = thread.did_crash() - if options.crashed_only and this_thread_crashed == False: - continue - print "%s" % thread - #prev_frame_index = -1 - for frame_idx, frame in enumerate(thread.frames): - disassemble = (this_thread_crashed or options.disassemble_all_threads) and frame_idx < options.disassemble_depth; - symbolicated_frame_addresses = crash_log.symbolicate (frame.pc) - if symbolicated_frame_addresses: - symbolicated_frame_address_idx = 0 - for symbolicated_frame_address in symbolicated_frame_addresses: - print '[%3u] %s' % (frame_idx, symbolicated_frame_address) - - if symbolicated_frame_address_idx == 0: - if disassemble: - instructions = symbolicated_frame_address.get_instructions() - if instructions: - print - symbolication.disassemble_instructions (target, - instructions, - frame.pc, - options.disassemble_before, - options.disassemble_after, frame.index > 0) - print - symbolicated_frame_address_idx += 1 - else: - print frame - print - - if options.dump_image_list: - print "Binary Images:" - for image in crash_log.images: - print image - -if __name__ == '__main__': - # Create a new debugger instance - lldb.debugger = lldb.SBDebugger.Create() - SymbolicateCrashLog (sys.argv[1:]) -elif lldb.debugger: - lldb.debugger.HandleCommand('command script add -f crashlog.Symbolicate crashlog') - print '"crashlog" command installed, type "crashlog --help" for detailed help' - diff --git a/lldb/examples/python/delta.py b/lldb/examples/python/delta.py deleted file mode 100755 index da17dd7ec499..000000000000 --- a/lldb/examples/python/delta.py +++ /dev/null @@ -1,115 +0,0 @@ -#!/usr/bin/python - -#---------------------------------------------------------------------- -# 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 -# 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" -# 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 -# available. -#---------------------------------------------------------------------- - -import commands -import optparse -import os -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 - 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) - else: - args_len = len(args) - if args_len == 0: - log_file = tempfile.mktemp() - elif len(args) == 1: - 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) - return - - 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 - # characters must be listed here - command_args = shlex.split(command) - 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) - try: - (options, args) = parser.parse_args(command_args) - except: - return - for log_file in args: - 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 fucntion 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 - for GDB remote commands to make a send/receive round trip. This can be - handy when trying to figure out why some operation in the debugger is taking - a long time during a preset set of debugger commands.''' - - print '#----------------------------------------------------------------------' - print "# Log file: '%s'" % file - print '#----------------------------------------------------------------------' - - timestamp_regex = re.compile('(\s*)([1-9][0-9]+\.[0-9]+)([^0-9].*)$') - - base_time = 0.0 - last_time = 0.0 - file = open(file) - lines = file.read().splitlines() - for line in lines: - match = timestamp_regex.match (line) - if match: - curr_time = float (match.group(2)) - delta = 0.0 - if base_time: - delta = curr_time - last_time - else: - base_time = curr_time - - print '%s%.6f %+.6f%s' % (match.group(1), curr_time - base_time, delta, match.group(3)) - last_time = curr_time - else: - print line - - - -if __name__ == '__main__': - import sys - parse_time_log_args (sys.argv[1:]) - -else: - import lldb - 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') - print 'The "parse_time_log" command is now installed and ready for use, type "parse_time_log --help" for more information' diff --git a/lldb/examples/python/disasm-stress-test.py b/lldb/examples/python/disasm-stress-test.py deleted file mode 100755 index 5aa354dc24cb..000000000000 --- a/lldb/examples/python/disasm-stress-test.py +++ /dev/null @@ -1,168 +0,0 @@ -#!/usr/bin/python - -import argparse, datetime, re, subprocess, sys, time - -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') - -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: - 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: - print "Couldn't find LLDB.framework" - sys.exit(-1) - - sys.path.append(lldb_framework_path + "/Resources/Python") - -if arg_ns.lldb == None: - AddLLDBToSysPathOnMacOSX() -else: - sys.path.append(arg_ns.lldb + "/Resources/Python") - -import lldb - -debugger = lldb.SBDebugger.Create() - -if debugger.IsValid() == False: - print "Couldn't create an SBDebugger" - sys.exit(-1) - -target = debugger.CreateTargetWithFileAndArch(None, arg_ns.arch) - -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 - self.m_start = start - 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 - 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: - 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: - raise StopIteration - return ret - -log_file = None - -def GetProviderWithArguments(args): - global log_file - if args.log != None: - log_file = open(args.log, 'w') - else: - log_file = sys.stdout - instruction_provider = None - if args.random == True: - instruction_provider = RandomInstructionProvider(args.bytes, log_file) - else: - start = 0 - skip = 1 - if args.start != None: - start = args.start - if args.skip != None: - skip = args.skip - instruction_provider = SequentialInstructionProvider(args.bytes, log_file, start, skip) - return instruction_provider - -instruction_provider = GetProviderWithArguments(arg_ns) - -fake_address = lldb.SBAddress() - -actually_time = arg_ns.time and not arg_ns.random - -if actually_time: - num_instructions_logged = 0 - total_num_instructions = instruction_provider.GetNumInstructions() - start_time = time.time() - -for inst_bytes in instruction_provider: - if actually_time: - 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)) - print str(datetime.timedelta(seconds=remaining_time)) - num_instructions_logged = num_instructions_logged + 1 - inst_list = target.GetInstructions(fake_address, inst_bytes) - if not inst_list.IsValid(): - print >>log_file, "Invalid instruction list" - continue - inst = inst_list.GetInstructionAtIndex(0) - if not inst.IsValid(): - print >>log_file, "Invalid instruction" - continue - instr_output_stream = lldb.SBStream() - inst.GetDescription(instr_output_stream) - print >>log_file, instr_output_stream.GetData() diff --git a/lldb/examples/python/disasm.py b/lldb/examples/python/disasm.py deleted file mode 100755 index 732cf106b11d..000000000000 --- a/lldb/examples/python/disasm.py +++ /dev/null @@ -1,119 +0,0 @@ -#!/usr/bin/python - -#---------------------------------------------------------------------- -# Be sure to add the python path that points to the LLDB shared library. -# On MacOSX csh, tcsh: -# setenv PYTHONPATH /Developer/Library/PrivateFrameworks/LLDB.framework/Resources/Python -# On MacOSX sh, bash: -# export PYTHONPATH=/Developer/Library/PrivateFrameworks/LLDB.framework/Resources/Python -#---------------------------------------------------------------------- - -import lldb -import os -import sys - -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." - sys.exit(0) - -if len(sys.argv) == 2: - fname = 'main' - exe = sys.argv[1] -elif len(sys.argv) == 4: - if sys.argv[1] != '-n': - usage() - else: - fname = sys.argv[2] - exe = sys.argv[3] -else: - usage() - -# Create a new debugger instance -debugger = lldb.SBDebugger.Create() - -# 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) - -# Create a target from a file and arch -print "Creating a target for '%s'" % exe - -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()); - - 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()) - - # Make sure the launch went ok - if process: - # Print some simple process info - state = process.GetState () - print process - if state == lldb.eStateStopped: - # Get the first thread - thread = process.GetThreadAtIndex (0) - if thread: - # Print some simple thread info - print thread - # Get the first frame - 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 - print function - # Now get all instructions for this function and print them - insts = function.GetInstructions(target) - disassemble_instructions (insts) - else: - # 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 - print symbol - # Now get all instructions for this symbol and print them - insts = symbol.GetInstructions(target) - disassemble_instructions (insts) - - registerList = frame.GetRegisters() - print "Frame registers (size of register set = %d):" % registerList.GetSize() - for value in registerList: - #print value - print "%s (number of children = %d):" % (value.GetName(), value.GetNumChildren()) - for child in value: - print "Name: ", child.GetName(), " Value: ", child.GetValue() - - print "Hit the breakpoint at main, enter to continue and wait for program to exit or 'Ctrl-D'/'quit' to terminate the program" - next = sys.stdin.readline() - if not next or next.rstrip('\n') == 'quit': - print "Terminating the inferior process..." - process.Kill() - else: - # Now continue to the program exit - process.Continue() - # When we return from the above function we will hopefully be at the - # program exit. Print out some process info - print process - 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) - process.Kill() - - - -lldb.SBDebugger.Terminate() diff --git a/lldb/examples/python/gdbremote.py b/lldb/examples/python/gdbremote.py deleted file mode 100755 index 4fcf82168af0..000000000000 --- a/lldb/examples/python/gdbremote.py +++ /dev/null @@ -1,197 +0,0 @@ -#!/usr/bin/python - -#---------------------------------------------------------------------- -# 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 -# 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" -# 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 -# available. -#---------------------------------------------------------------------- - -import commands -import optparse -import os -import shlex -import re -import tempfile - -log_file = '' - -def start_gdb_log(debugger, command, result, dict): - '''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 - command_args = shlex.split(command) - usage = "usage: start_gdb_log [options] [<LOGFILEPATH>]" - description='''The command enables GDB remote packet logging with timestamps. The packets will be logged to <LOGFILEPATH> if supplied, or a temporary file will be used. Logging stops when stop_gdb_log is called and the packet times will - be aggregated and displayed.''' - parser = optparse.OptionParser(description=description, prog='start_gdb_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 - - if log_file: - result.PutCString ('error: logging is already in progress with file "%s"', log_file) - else: - args_len = len(args) - if args_len == 0: - log_file = tempfile.mktemp() - elif len(args) == 1: - 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) - return - - result.PutCString ('error: invalid log file path') - result.PutCString (usage) - -def stop_gdb_log(debugger, command, result, dict): - '''Stop logging GDB remote packets to the file that was specified in a call - to "start_gdb_log" and normalize the timestamps to be relative to the first - timestamp in the log file. Also print out statistics for how long each - command took to allow performance bottlenecks to be determined.''' - global log_file - # Any commands whose names might be followed by more valid C identifier - # characters must be listed here - command_args = shlex.split(command) - usage = "usage: stop_gdb_log [options]" - description='''The command stops a previously enabled GDB remote packet logging command. Packet logging must have been previously enabled with a call to start_gdb_log.''' - parser = optparse.OptionParser(description=description, prog='stop_gdb_log',usage=usage) - parser.add_option('-v', '--verbose', action='store_true', dest='verbose', help='display verbose debug info', default=False) - parser.add_option('-q', '--quiet', action='store_true', dest='quiet', help='display verbose debug info', default=False) - parser.add_option('-c', '--sort-by-count', action='store_true', dest='sort_count', help='display verbose debug info', default=False) - try: - (options, args) = parser.parse_args(command_args) - except: - return - - if not log_file: - result.PutCString ('error: logging must have been previously enabled with a call to "stop_gdb_log"') - elif os.path.exists (log_file): - if len(args) == 0: - debugger.HandleCommand('log disable gdb-remote packets'); - result.PutCString ("GDB packet logging disabled. Logged packets are in '%s'" % log_file) - parse_gdb_log_file (log_file, options) - log_file = None - else: - result.PutCString (usage) - else: - print 'error: the GDB packet log file "%s" does not exist' % log_file - -def parse_gdb_log_file(file, options): - '''Parse a GDB log file that was generated by enabling logging with: - (lldb) log enable --threadsafe --timestamp --file <FILE> gdb-remote packets - This log file will contain timestamps and this fucntion 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 - for GDB remote commands to make a send/receive round trip. This can be - handy when trying to figure out why some operation in the debugger is taking - a long time during a preset set of debugger commands.''' - - tricky_commands = [ 'qRegisterInfo' ] - timestamp_regex = re.compile('(\s*)([1-9][0-9]+\.[0-9]+)([^0-9].*)$') - packet_name_regex = re.compile('([A-Za-z_]+)[^a-z]') - base_time = 0.0 - last_time = 0.0 - packet_send_time = 0.0 - packet_name = None - packet_total_times = {} - packet_count = {} - file = open(file) - lines = file.read().splitlines() - for line in lines: - match = timestamp_regex.match (line) - if match: - curr_time = float (match.group(2)) - delta = 0.0 - if base_time: - delta = curr_time - last_time - else: - base_time = curr_time - idx = line.find('send packet: $') - if idx >= 0: - packet_send_time = curr_time - packet_match = packet_name_regex.match (line[idx+14:]) - if packet_match: - packet_name = packet_match.group(1) - for tricky_cmd in tricky_commands: - if packet_name.find (tricky_cmd) == 0: - packet_name = tricky_cmd - elif line.find('read packet: $') >= 0 and packet_name: - if packet_name in packet_total_times: - packet_total_times[packet_name] += delta - packet_count[packet_name] += 1 - else: - packet_total_times[packet_name] = delta - packet_count[packet_name] = 1 - packet_name = None - - if not options or not options.quiet: - print '%s%.6f %+.6f%s' % (match.group(1), curr_time - base_time, delta, match.group(3)) - last_time = curr_time - else: - print line - if packet_total_times: - total_packet_time = 0.0 - total_packet_count = 0 - for key, vvv in packet_total_times.items(): - # print ' key = (%s) "%s"' % (type(key), key) - # print 'value = (%s) %s' % (type(vvv), vvv) - # if type(vvv) == 'float': - total_packet_time += vvv - for key, vvv in packet_count.items(): - total_packet_count += vvv - - print '#---------------------------------------------------' - print '# Packet timing summary:' - print '# Totals: time - %6f count %6d' % (total_packet_time, total_packet_count) - print '#---------------------------------------------------' - print '# Packet Time (sec) Percent Count ' - print '#------------------------- ---------- ------- ------' - if options and options.sort_count: - res = sorted(packet_count, key=packet_count.__getitem__, reverse=True) - else: - res = sorted(packet_total_times, key=packet_total_times.__getitem__, reverse=True) - - if last_time > 0.0: - for item in res: - packet_total_time = packet_total_times[item] - packet_percent = (packet_total_time / total_packet_time)*100.0 - if packet_percent >= 10.0: - print " %24s %.6f %.2f%% %6d" % (item, packet_total_time, packet_percent, packet_count[item]) - else: - print " %24s %.6f %.2f%% %6d" % (item, packet_total_time, packet_percent, packet_count[item]) - - - -if __name__ == '__main__': - import sys - # This script is being run from the command line, create a debugger in case we are - # going to use any debugger functions in our function. - for file in sys.argv[1:]: - print '#----------------------------------------------------------------------' - print "# GDB remote log file: '%s'" % file - print '#----------------------------------------------------------------------' - parse_gdb_log_file (file, None) - -else: - import lldb - 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 gdbremote.start_gdb_log start_gdb_log') - lldb.debugger.HandleCommand('command script add -f gdbremote.stop_gdb_log stop_gdb_log') - print 'The "start_gdb_log" and "stop_gdb_log" commands are now installed and ready for use, type "start_gdb_log --help" or "stop_gdb_log --help" for more information' diff --git a/lldb/examples/python/sbvalue.py b/lldb/examples/python/sbvalue.py deleted file mode 100755 index 59c0b61e5528..000000000000 --- a/lldb/examples/python/sbvalue.py +++ /dev/null @@ -1,255 +0,0 @@ -#!/usr/bin/python - -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 - argv = a.value(lldb.frame.FindVariable('argv'))\n - argv.name - return the name of the value that this object contains\n - argv.type - return the lldb.SBType for this value - argv.type_name - return the name of the type - argv.size - return the byte size of this value - argv.is_in_scope - return true if this value is currently in scope - argv.is_pointer - return true if this value is a pointer - argv.format - return the current format for this value - argv.value - return the value's value as a string - argv.summary - return a summary of this value's value - argv.description - return the runtime description for this value - argv.location - return a string that represents the values location (address, register, etc) - argv.target - return the lldb.SBTarget for this value - argv.process - return the lldb.SBProcess for this value - argv.thread - return the lldb.SBThread for this value - argv.frame - return the lldb.SBFrame for this value - 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 - - def __nonzero__(self): - return self.sbvalue.__nonzero__() - - def __repr__(self): - return self.sbvalue.__repr__() - - def __str__(self): - return self.sbvalue.__str__() - - def __getitem__(self, key): - if type(key) is int: - return value(self.sbvalue.GetChildAtIndex(key, lldb.eNoDynamicValues, True)) - raise TypeError - - def __getattr__(self, name): - if name == 'name': - return self.sbvalue.GetName() - if name == 'type': - return self.sbvalue.GetType() - if name == 'type_name': - return self.sbvalue.GetTypeName() - if name == 'size': - return self.sbvalue.GetByteSize() - if name == 'is_in_scope': - return self.sbvalue.IsInScope() - if name == 'is_pointer': - return self.sbvalue.TypeIsPointerType() - if name == 'format': - return self.sbvalue.GetFormat () - if name == 'value': - return self.sbvalue.GetValue () - if name == 'summary': - return self.sbvalue.GetSummary () - if name == 'description': - return self.sbvalue.GetObjectDescription () - if name == 'location': - return self.sbvalue.GetLocation () - if name == 'target': - return self.sbvalue.GetTarget() - if name == 'process': - return self.sbvalue.GetProcess() - if name == 'thread': - return self.sbvalue.GetThread() - if name == 'frame': - return self.sbvalue.GetFrame() - if name == 'num_children': - return self.sbvalue.GetNumChildren() - if name == 'children': - # 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))) - 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 - in your code, you would be able to do: "pt.x + pt.y"''' - def __init__(self, sbvalue): - self.sbvalue = sbvalue - - def __nonzero__(self): - return self.sbvalue.__nonzero__() - - def __repr__(self): - return self.sbvalue.__repr__() - - def __str__(self): - return self.sbvalue.__str__() - - def __getitem__(self, key): - # Allow array access if this value has children... - if type(key) is int: - return variable(self.sbvalue.GetValueForExpressionPath("[%i]" % key)) - raise TypeError - - def __getattr__(self, 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)) - return result - - def __isub__(self, other): - result = self.__sub__(other) - self.sbvalue.SetValueFromCString (str(result)) - return result - - def __imul__(self, other): - result = self.__mul__(other) - self.sbvalue.SetValueFromCString (str(result)) - return result - - def __idiv__(self, other): - result = self.__div__(other) - self.sbvalue.SetValueFromCString (str(result)) - return result - - def __itruediv__(self, other): - result = self.__truediv__(other) - self.sbvalue.SetValueFromCString (str(result)) - return result - - def __ifloordiv__(self, other): - 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)) - return result - - def __ipow__(self, other): - result = self.__pow__(self, other) - self.sbvalue.SetValueFromCString (str(result)) - return result - - def __ipow__(self, other, modulo): - result = self.__pow__(self, other, modulo) - self.sbvalue.SetValueFromCString (str(result)) - return result - - def __ilshift__(self, other): - result = self.__lshift__(self, other) - self.sbvalue.SetValueFromCString (str(result)) - return result - - def __irshift__(self, other): - 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)) - return result - - def __ixor__(self, other): - 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)) - 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)) - - def __int__(self): - return self.sbvalue.GetValueAsSigned() - - def __long__(self): - return self.sbvalue.GetValueAsSigned() - - def __float__(self): - return float (self.sbvalue.GetValueAsSigned()) - - def __oct__(self): - return '0%o' % self.sbvalue.GetValueAsSigned() - - def __hex__(self): - return '0x%x' % self.sbvalue.GetValueAsSigned() -
\ No newline at end of file diff --git a/lldb/examples/python/symbolication.py b/lldb/examples/python/symbolication.py deleted file mode 100755 index 0e9aa070ee6f..000000000000 --- a/lldb/examples/python/symbolication.py +++ /dev/null @@ -1,524 +0,0 @@ -#!/usr/bin/python - -#---------------------------------------------------------------------- -# Be sure to add the python path that points to the LLDB shared library. -# -# To use this in the embedded python interpreter using "lldb": -# -# cd /path/containing/crashlog.py -# lldb -# (lldb) script import crashlog -# "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 -# 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. -# -# On MacOSX csh, tcsh: -# ( setenv PYTHONPATH /path/to/LLDB.framework/Resources/Python ; ./crashlog.py ~/Library/Logs/DiagnosticReports/a.crash ) -# -# On MacOSX sh, bash: -# PYTHONPATH=/path/to/LLDB.framework/Resources/Python ./crashlog.py ~/Library/Logs/DiagnosticReports/a.crash -#---------------------------------------------------------------------- - -import lldb -import commands -import optparse -import os -import plistlib -import re -import shlex -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.inlined = False - def __str__(self): - s = "%#16.16x" % (self.load_addr) - if self.symbolication: - s += " %s" % (self.symbolication) - elif self.description: - s += " %s" % (self.description) - elif self.so_addr: - s += " %s" % (self.so_addr) - return s - - def resolve_addr(self): - if self.so_addr == 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: - sb_addr = self.resolve_addr() - if sb_addr: - self.sym_ctx = self.target.ResolveSymbolContextForAddress (sb_addr, lldb.eSymbolContextEverything) - else: - self.sym_ctx = lldb.SBSymbolContext() - return self.sym_ctx - - def get_instructions(self): - sym_ctx = self.get_symbol_context() - if sym_ctx: - function = sym_ctx.GetFunction() - if function: - return function.GetInstructions(self.target) - return sym_ctx.GetSymbol().GetInstructions(self.target) - return None - - def symbolicate(self): - if self.symbolication == None: - self.symbolication = '' - self.inlined = False - sym_ctx = self.get_symbol_context() - if sym_ctx: - module = sym_ctx.GetModule() - if module: - self.symbolication += module.GetFileSpec().GetFilename() + '`' - function_start_load_addr = -1 - function = sym_ctx.GetFunction() - block = sym_ctx.GetBlock() - line_entry = sym_ctx.GetLineEntry() - symbol = sym_ctx.GetSymbol() - 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) - 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) - if function_start_load_addr == -1: - function_start_load_addr = function.GetStartAddress().GetLoadAddress (self.target) - elif symbol: - self.symbolication += symbol.GetName() - 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 - function_offset = self.load_addr - function_start_load_addr - if function_offset > 0: - self.symbolication += " + %u" % (function_offset) - elif function_offset < 0: - self.symbolication += " %i (invalid negative offset, file a bug) " % function_offset - - # Print out any line information if any is available - if line_entry.GetFileSpec(): - self.symbolication += ' at %s' % line_entry.GetFileSpec().GetFilename() - 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*$') - - def __init__(self, start_addr = None, end_addr = None, name = None): - self.start_addr = start_addr - self.end_addr = end_addr - self.name = name - - def contains(self, addr): - return self.start_addr <= addr and addr < self.end_addr; - - def set_from_string(self, s): - match = self.sect_info_regex.match (s) - if match: - self.name = match.group('name') - range_str = match.group('range') - addr_match = self.addr_regex.match(range_str) - if addr_match: - self.start_addr = int(addr_match.group('start'), 16) - self.end_addr = None - return True - - range_match = self.range_regex.match(range_str) - if range_match: - self.start_addr = int(range_match.group('start'), 16) - self.end_addr = int(range_match.group('end'), 16) - op = range_match.group('op') - if op == '+': - self.end_addr += self.start_addr - return True - print 'error: invalid section info string "%s"' % s - print 'Valid section info formats are:' - print 'Format Example Description' - print '--------------------- -----------------------------------------------' - print '<name>=<base> __TEXT=0x123000 Section from base address only' - 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) - else: - if self.start_addr != 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): - self.path = path - self.resolved_path = None - self.uuid = uuid - self.section_infos = list() - self.identifier = None - self.version = None - self.arch = None - self.module = None - self.symfile = None - self.slide = None - - def dump(self, prefix): - print "%s%s" % (prefix, self) - - def __str__(self): - s = "%s %s" % (self.get_uuid(), self.get_resolved_path()) - for section_info in self.section_infos: - s += ", %s" % (section_info) - if self.slide != None: - s += ', slide = 0x%16.16x' % self.slide - 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): - for section_info in self.section_infos: - if section_info.contains(load_addr): - return section_info - return None - - def get_resolved_path(self): - if self.resolved_path: - return self.resolved_path - elif self.path: - return self.path - return None - - def get_resolved_path_basename(self): - path = self.get_resolved_path() - if path: - return os.path.basename(path) - return None - - def symfile_basename(self): - 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 - - def load_module(self, target): - # Load this module into "target" using the section infos to - # set the section load addresses - if self.has_section_load_info(): - if target: - if self.module: - if self.section_infos: - num_sections_loaded = 0 - for section_info in self.section_infos: - if section_info.name: - section = self.module.FindSection (section_info.name) - if section: - error = target.SetSectionLoadAddress (section, section_info.start_addr) - if error.Success(): - num_sections_loaded += 1 - else: - return 'error: %s' % error.GetCString() - 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()) - if num_sections_loaded == 0: - return 'error: no sections were successfully loaded' - else: - err = target.SetModuleLoadAddress(self.module, self.slide) - if err.Fail(): - return err.GetCString() - return None - else: - return 'error: invalid module' - else: - 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: - resolved_path = self.get_resolved_path(); - # Try and find using UUID only first so that paths need not match up - if self.uuid: - self.module = target.AddModule (None, None, str(self.uuid)) - if not self.module: - if self.locate_module_and_debug_symbols (): - path_spec = lldb.SBFileSpec (resolved_path) - #print 'target.AddModule (path="%s", arch="%s", uuid=%s)' % (resolved_path, self.arch, self.uuid) - self.module = target.AddModule (resolved_path, self.arch, self.uuid) - if not self.module: - return 'error: unable to get module for (%s) "%s"' % (self.arch, 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 - else: - return 'error: invalid target' - - def locate_module_and_debug_symbols (self): - # By default, just use the paths that were supplied in: - # self.path - # self.resolved_path - # self.module - # self.symfile - # Subclasses can inherit from this class and override this function - return True - - def get_uuid(self): - if not self.uuid: - self.uuid = uuid.UUID(self.module.GetUUIDString()) - return self.uuid - - def create_target(self): - '''Create a target using the information in this Image object.''' - 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); - if target: - self.module = target.FindModule(path_spec) - if self.has_section_load_info(): - err = self.load_module(target) - if err: - print 'ERROR: ', err - return target - else: - print 'error: unable to create a valid target for (%s) "%s"' % (self.arch, self.path) - 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 - - - def __str__(self): - s = "Symbolicator:\n" - if self.target: - s += "Target = '%s'\n" % (self.target) - s += "Target modules:'\n" - for m in self.target.modules: - print m - s += "Images:\n" - 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: - if image.identifier == identifier: - images.append(image) - return images - - def find_image_containing_load_addr(self, load_addr): - for image in self.images: - if image.contains_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 () - if self.target: - return self.target - return None - - def symbolicate(self, load_addr): - if self.target: - symbolicated_address = Address(self.target, load_addr) - if symbolicated_address.symbolicate (): - - if symbolicated_address.so_addr: - symbolicated_addresses = list() - symbolicated_addresses.append(symbolicated_address) - # See if we were able to reconstruct anything? - while 1: - inlined_parent_so_addr = lldb.SBAddress() - 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.sym_ctx = inlined_parent_sym_ctx - symbolicated_address.so_addr = inlined_parent_so_addr - symbolicated_address.symbolicate () - - # push the new frame onto the new frame stack - symbolicated_addresses.append (symbolicated_address) - - if symbolicated_addresses: - return symbolicated_addresses - return None - - -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); - if pc == inst_pc: - pc_index = inst_idx - 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)) - if comment: - line_len = len(lines[-1]) - if line_len < comment_column: - lines[-1] += ' ' * (comment_column - line_len) - 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 non_zeroeth_frame and pc_index > 0: - pc_index = pc_index - 1 - if insts_before_pc == -1: - start_idx = 0 - else: - start_idx = pc_index - insts_before_pc - if start_idx < 0: - start_idx = 0 - if insts_before_pc == -1: - end_idx = inst_idx - else: - 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): - if i == pc_index: - print ' -> ', lines[i] - else: - print ' ', lines[i] - -def print_module_section_data (section): - print section - section_data = section.GetSectionData() - if section_data: - ostream = lldb.SBStream() - section_data.GetDescription (ostream, section.GetFileAddress()) - print ostream.GetData() - -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) - -def print_module_sections (module, depth): - for sect in module.section_iter(): - print_module_section (sect, depth) - -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 one platform by name') - 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(); - if options.file: - image = Image(options.file); - image.arch = options.arch - # 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) - else: - sys.exit(1) - if options.slide != 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) - 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:]) |
