summaryrefslogtreecommitdiff
path: root/examples/python
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2016-01-06 20:12:03 +0000
committerDimitry Andric <dim@FreeBSD.org>2016-01-06 20:12:03 +0000
commit9e6d35490a6542f9c97607f93c2ef8ca8e03cbcc (patch)
treedd2a1ddf0476664c2b823409c36cbccd52662ca7 /examples/python
parent3bd2e91faeb9eeec1aae82c64a3253afff551cfd (diff)
Notes
Diffstat (limited to 'examples/python')
-rw-r--r--examples/python/cmdtemplate.py76
-rwxr-xr-xexamples/python/crashlog.py829
-rwxr-xr-xexamples/python/delta.py115
-rw-r--r--examples/python/diagnose_nsstring.py171
-rw-r--r--examples/python/diagnose_unwind.py270
-rwxr-xr-xexamples/python/dict_utils.py61
-rwxr-xr-xexamples/python/disasm-stress-test.py168
-rwxr-xr-xexamples/python/disasm.py119
-rwxr-xr-xexamples/python/file_extract.py221
-rwxr-xr-xexamples/python/gdb_disassemble.py24
-rwxr-xr-xexamples/python/gdbremote.py1362
-rwxr-xr-xexamples/python/globals.py72
-rw-r--r--examples/python/jump.py173
-rw-r--r--examples/python/lldb_module_utils.py59
-rw-r--r--examples/python/lldbtk.py544
-rwxr-xr-xexamples/python/mach_o.py1687
-rwxr-xr-xexamples/python/memory.py181
-rw-r--r--examples/python/operating_system.py104
-rwxr-xr-xexamples/python/performance.py335
-rwxr-xr-xexamples/python/process_events.py278
-rw-r--r--examples/python/pytracer.py328
-rwxr-xr-xexamples/python/sbvalue.py255
-rw-r--r--examples/python/scripted_step.py186
-rw-r--r--examples/python/sources.py28
-rwxr-xr-xexamples/python/stacks.py59
-rwxr-xr-xexamples/python/symbolication.py640
-rwxr-xr-xexamples/python/types.py265
-rw-r--r--examples/python/x86_64_linux_target_definition.py353
-rw-r--r--examples/python/x86_64_qemu_target_definition.py352
-rw-r--r--examples/python/x86_64_target_definition.py357
30 files changed, 9672 insertions, 0 deletions
diff --git a/examples/python/cmdtemplate.py b/examples/python/cmdtemplate.py
new file mode 100644
index 0000000000000..ca575362f9b7e
--- /dev/null
+++ b/examples/python/cmdtemplate.py
@@ -0,0 +1,76 @@
+#!/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
+#----------------------------------------------------------------------
+
+import lldb
+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
+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
+
+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.'
diff --git a/examples/python/crashlog.py b/examples/python/crashlog.py
new file mode 100755
index 0000000000000..60a6a1f50f005
--- /dev/null
+++ b/examples/python/crashlog.py
@@ -0,0 +1,829 @@
+#!/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 commands
+import cmd
+import datetime
+import glob
+import optparse
+import os
+import platform
+import plistlib
+import pprint # pp = pprint.PrettyPrinter(indent=4); pp.pprint(command_args)
+import re
+import shlex
+import string
+import sys
+import time
+import uuid
+
+try:
+ # Just try for LLDB in case PYTHONPATH is already correctly setup
+ import lldb
+except ImportError:
+ lldb_python_dirs = list()
+ # lldb is not in the PYTHONPATH, try some defaults for the current platform
+ platform_system = platform.system()
+ if platform_system == 'Darwin':
+ # 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')
+ 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:
+ import lldb
+ except ImportError:
+ pass
+ else:
+ print 'imported lldb from: "%s"' % (lldb_python_dir)
+ success = True
+ break
+ if not success:
+ print "error: couldn't locate the 'lldb' module, please set PYTHONPATH correctly"
+ sys.exit(1)
+
+from lldb.utils 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"""
+ parent_process_regex = re.compile('^Parent Process:\s*(.*)\[(\d+)\]');
+ thread_state_regex = re.compile('^Thread ([0-9]+) crashed with')
+ thread_regex = re.compile('^Thread ([0-9]+)([^:]*):(.*)')
+ app_backtrace_regex = re.compile('^Application Specific Backtrace ([0-9]+)([^:]*):(.*)')
+ frame_regex = re.compile('^([0-9]+)\s+([^ ]+)\s+(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, app_specific_backtrace):
+ self.index = index
+ self.frames = list()
+ self.idents = list()
+ self.registers = dict()
+ self.reason = None
+ self.queue = None
+ self.app_specific_backtrace = app_specific_backtrace
+
+ def dump(self, prefix):
+ if self.app_specific_backtrace:
+ print "%Application Specific Backtrace[%u] %s" % (prefix, self.index, self.reason)
+ else:
+ 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 dump_symbolicated (self, crash_log, options):
+ this_thread_crashed = self.app_specific_backtrace
+ if not this_thread_crashed:
+ this_thread_crashed = self.did_crash()
+ if options.crashed_only and this_thread_crashed == False:
+ return
+
+ print "%s" % self
+ #prev_frame_index = -1
+ display_frame_idx = -1
+ for frame_idx, frame in enumerate(self.frames):
+ disassemble = (this_thread_crashed or options.disassemble_all_threads) and frame_idx < options.disassemble_depth;
+ if frame_idx == 0:
+ symbolicated_frame_addresses = crash_log.symbolicate (frame.pc & crash_log.addr_mask, options.verbose)
+ else:
+ # Any frame above frame zero and we have to subtract one to get the previous line entry
+ symbolicated_frame_addresses = crash_log.symbolicate ((frame.pc & crash_log.addr_mask) - 1, options.verbose)
+
+ if symbolicated_frame_addresses:
+ symbolicated_frame_address_idx = 0
+ for symbolicated_frame_address in symbolicated_frame_addresses:
+ display_frame_idx += 1
+ print '[%3u] %s' % (frame_idx, symbolicated_frame_address)
+ if (options.source_all or self.did_crash()) and display_frame_idx < options.source_frames and options.source_context:
+ source_context = options.source_context
+ line_entry = symbolicated_frame_address.get_symbol_context().line_entry
+ if line_entry.IsValid():
+ strm = lldb.SBStream()
+ if line_entry:
+ lldb.debugger.GetSourceManager().DisplaySourceLinesWithLineNumbers(line_entry.file, line_entry.line, source_context, source_context, "->", strm)
+ source_text = strm.GetData()
+ if source_text:
+ # Indent the source a bit
+ indent_str = ' '
+ join_str = '\n' + indent_str
+ print '%s%s' % (indent_str, join_str.join(source_text.split('\n')))
+ if symbolicated_frame_address_idx == 0:
+ if disassemble:
+ instructions = symbolicated_frame_address.get_instructions()
+ if instructions:
+ print
+ symbolication.disassemble_instructions (crash_log.get_target(),
+ instructions,
+ frame.pc,
+ options.disassemble_before,
+ options.disassemble_after, frame.index > 0)
+ print
+ symbolicated_frame_address_idx += 1
+ else:
+ print frame
+
+ def add_ident(self, ident):
+ if not ident in self.idents:
+ self.idents.append(ident)
+
+ def did_crash(self):
+ return self.reason != None
+
+ def __str__(self):
+ if self.app_specific_backtrace:
+ s = "Application Specific Backtrace[%u]" % self.index
+ else:
+ 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)
+
+ def dump(self, prefix):
+ print "%s%s" % (prefix, str(self))
+
+ 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):
+ # Don't load a module twice...
+ if self.resolved:
+ return True
+ # Mark this as resolved so we don't keep trying
+ self.resolved = True
+ uuid_str = self.get_normalized_uuid_string()
+ print 'Getting symbols for %s %s...' % (uuid_str, self.path),
+ if os.path.exists(self.dsymForUUIDBinary):
+ dsym_for_uuid_command = '%s %s' % (self.dsymForUUIDBinary, uuid_str)
+ s = commands.getoutput(dsym_for_uuid_command)
+ if s:
+ plist_root = plistlib.readPlistFromString (s)
+ if plist_root:
+ plist = plist_root[uuid_str]
+ 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.path = os.path.expanduser (plist['DBGSymbolRichExecutable'])
+ self.resolved_path = self.path
+ if not self.resolved_path and os.path.exists(self.path):
+ dwarfdump_cmd_output = commands.getoutput('dwarfdump --uuid "%s"' % self.path)
+ self_uuid = self.get_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:
+ self.unavailable = True
+ print "error\n error: unable to locate '%s' with UUID %s" % (self.path, uuid_str)
+ return False
+ if (self.resolved_path and os.path.exists(self.resolved_path)) or (self.path and os.path.exists(self.path)):
+ print 'ok'
+ # if self.resolved_path:
+ # print ' exe = "%s"' % self.resolved_path
+ # if self.symfile:
+ # print ' dsym = "%s"' % self.symfile
+ return True
+ else:
+ self.unavailable = True
+ return False
+
+
+
+ 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.backtraces = list() # For application specific backtraces
+ 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
+ self.target = 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
+ app_specific_backtrace = False
+ 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
+ if app_specific_backtrace:
+ self.backtraces.append(thread)
+ else:
+ 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:'):
+ version_string = line[8:].strip()
+ matched_pair = re.search("(.+)\((.+)\)", version_string)
+ if matched_pair:
+ self.process_version = matched_pair.group(1)
+ self.process_compatability_version = matched_pair.group(2)
+ else:
+ self.process = version_string
+ self.process_compatability_version = version_string
+ elif self.parent_process_regex.search(line):
+ parent_process_match = self.parent_process_regex.search(line)
+ self.parent_process_name = parent_process_match.group(1)
+ self.parent_process_id = parent_process_match.group(2)
+ 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:
+ app_specific_backtrace = False
+ 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:
+ app_specific_backtrace = False
+ parse_mode = PARSE_MODE_THREAD
+ thread_idx = int(thread_match.group(1))
+ thread = CrashLog.Thread(thread_idx, False)
+ continue
+ elif line.startswith ('Binary Images:'):
+ parse_mode = PARSE_MODE_IMAGES
+ continue
+ elif line.startswith ('Application Specific Backtrace'):
+ app_backtrace_match = self.app_backtrace_regex.search (line)
+ if app_backtrace_match:
+ parse_mode = PARSE_MODE_THREAD
+ app_specific_backtrace = True
+ idx = int(app_backtrace_match.group(1))
+ thread = CrashLog.Thread(idx, True)
+ self.info_lines.append(line.strip())
+ elif parse_mode == PARSE_MODE_THREAD:
+ if line.startswith ('Thread'):
+ continue
+ frame_match = self.frame_regex.search(line)
+ if frame_match:
+ ident = frame_match.group(2)
+ thread.add_ident(ident)
+ 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(),
+ uuid.UUID(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()
+ # "r12: 0x00007fff6b5939c8 r13: 0x0000000007000006 r14: 0x0000000000002a03 r15: 0x0000000000000c00"
+ reg_values = re.findall ('([a-zA-Z0-9]+: 0[Xx][0-9a-fA-F]+) *', stripped_line);
+ for reg_value in reg_values:
+ #print 'reg_value = "%s"' % reg_value
+ (reg, value) = reg_value.split(': ')
+ #print 'reg = "%s"' % reg
+ #print 'value = "%s"' % value
+ 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)
+ if self.backtraces:
+ print "\nApplication Specific Backtraces:"
+ for thread in self.backtraces:
+ thread.dump(' ')
+ 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
+ regex_text = '^.*\.%s$' % (identifier)
+ regex = re.compile(regex_text)
+ for image in self.images:
+ if regex.match(image.identifier):
+ return image
+ return None
+
+ def create_target(self):
+ #print 'crashlog.create_target()...'
+ if self.target is None:
+ self.target = symbolication.Symbolicator.create_target(self)
+ if self.target:
+ return self.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:
+ self.target = image.create_target ()
+ if self.target:
+ return self.target # success
+ print 'crashlog.create_target()...3'
+ for image in self.images:
+ self.target = image.create_target ()
+ if self.target:
+ return self.target # success
+ print 'crashlog.create_target()...4'
+ print 'error: unable to locate any executables from the crash log'
+ return self.target
+
+ def get_target(self):
+ return self.target
+
+def usage():
+ print "Usage: lldb-symbolicate.py [-n name] executable-image"
+ sys.exit(0)
+
+class Interactive(cmd.Cmd):
+ '''Interactive prompt for analyzing one or more Darwin crash logs, type "help" to see a list of supported commands.'''
+ image_option_parser = None
+
+ def __init__(self, crash_logs):
+ cmd.Cmd.__init__(self)
+ self.use_rawinput = False
+ self.intro = 'Interactive crashlogs prompt, type "help" to see a list of supported commands.'
+ self.crash_logs = crash_logs
+ self.prompt = '% '
+
+ def default(self, line):
+ '''Catch all for unknown command, which will exit the interpreter.'''
+ print "uknown command: %s" % line
+ return True
+
+ def do_q(self, line):
+ '''Quit command'''
+ return True
+
+ def do_quit(self, line):
+ '''Quit command'''
+ return True
+
+ def do_symbolicate(self, line):
+ description='''Symbolicate one or more darwin crash log files by index 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.'''
+ option_parser = CreateSymbolicateCrashLogOptions ('symbolicate', description, False)
+ command_args = shlex.split(line)
+ try:
+ (options, args) = option_parser.parse_args(command_args)
+ except:
+ return
+
+ if args:
+ # We have arguments, they must valid be crash log file indexes
+ for idx_str in args:
+ idx = int(idx_str)
+ if idx < len(self.crash_logs):
+ SymbolicateCrashLog (self.crash_logs[idx], options)
+ else:
+ print 'error: crash log index %u is out of range' % (idx)
+ else:
+ # No arguments, symbolicate all crash logs using the options provided
+ for idx in range(len(self.crash_logs)):
+ SymbolicateCrashLog (self.crash_logs[idx], options)
+
+ def do_list(self, line=None):
+ '''Dump a list of all crash logs that are currently loaded.
+
+ USAGE: list'''
+ print '%u crash logs are loaded:' % len(self.crash_logs)
+ for (crash_log_idx, crash_log) in enumerate(self.crash_logs):
+ print '[%u] = %s' % (crash_log_idx, crash_log.path)
+
+ def do_image(self, line):
+ '''Dump information about one or more binary images in the crash log given an image basename, or all images if no arguments are provided.'''
+ usage = "usage: %prog [options] <PATH> [PATH ...]"
+ description='''Dump information about one or more images in all crash logs. The <PATH> can be a full path, image basename, or partial path. Searches are done in this order.'''
+ command_args = shlex.split(line)
+ if not self.image_option_parser:
+ self.image_option_parser = optparse.OptionParser(description=description, prog='image',usage=usage)
+ self.image_option_parser.add_option('-a', '--all', action='store_true', help='show all images', default=False)
+ try:
+ (options, args) = self.image_option_parser.parse_args(command_args)
+ except:
+ return
+
+ if args:
+ for image_path in args:
+ fullpath_search = image_path[0] == '/'
+ for (crash_log_idx, crash_log) in enumerate(self.crash_logs):
+ matches_found = 0
+ for (image_idx, image) in enumerate(crash_log.images):
+ if fullpath_search:
+ if image.get_resolved_path() == image_path:
+ matches_found += 1
+ print '[%u] ' % (crash_log_idx), image
+ else:
+ image_basename = image.get_resolved_path_basename()
+ if image_basename == image_path:
+ matches_found += 1
+ print '[%u] ' % (crash_log_idx), image
+ if matches_found == 0:
+ for (image_idx, image) in enumerate(crash_log.images):
+ resolved_image_path = image.get_resolved_path()
+ if resolved_image_path and string.find(image.get_resolved_path(), image_path) >= 0:
+ print '[%u] ' % (crash_log_idx), image
+ else:
+ for crash_log in self.crash_logs:
+ for (image_idx, image) in enumerate(crash_log.images):
+ print '[%u] %s' % (image_idx, image)
+ return False
+
+
+def interactive_crashlogs(options, args):
+ crash_log_files = list()
+ for arg in args:
+ for resolved_path in glob.glob(arg):
+ crash_log_files.append(resolved_path)
+
+ crash_logs = list();
+ for crash_log_file in crash_log_files:
+ #print 'crash_log_file = "%s"' % crash_log_file
+ crash_log = CrashLog(crash_log_file)
+ if crash_log.error:
+ print crash_log.error
+ continue
+ if options.debug:
+ crash_log.dump()
+ if not crash_log.images:
+ print 'error: no images in crash log "%s"' % (crash_log)
+ continue
+ else:
+ crash_logs.append(crash_log)
+
+ interpreter = Interactive(crash_logs)
+ # List all crash logs that were imported
+ interpreter.do_list()
+ interpreter.cmdloop()
+
+
+def save_crashlog(debugger, command, result, dict):
+ usage = "usage: %prog [options] <output-path>"
+ description='''Export the state of current target into a crashlog file'''
+ parser = optparse.OptionParser(description=description, prog='save_crashlog',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(shlex.split(command))
+ except:
+ result.PutCString ("error: invalid options");
+ return
+ if len(args) != 1:
+ result.PutCString ("error: invalid arguments, a single output file is the only valid argument")
+ return
+ out_file = open(args[0], 'w')
+ if not out_file:
+ result.PutCString ("error: failed to open file '%s' for writing...", args[0]);
+ return
+ target = debugger.GetSelectedTarget()
+ if target:
+ identifier = target.executable.basename
+ if lldb.process:
+ pid = lldb.process.id
+ if pid != lldb.LLDB_INVALID_PROCESS_ID:
+ out_file.write('Process: %s [%u]\n' % (identifier, pid))
+ out_file.write('Path: %s\n' % (target.executable.fullpath))
+ out_file.write('Identifier: %s\n' % (identifier))
+ out_file.write('\nDate/Time: %s\n' % (datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")))
+ out_file.write('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]
+ out_file.write('\nThread %u:\n' % (thread_idx))
+ for (frame_idx, frame) in enumerate(thread.frames):
+ frame_pc = frame.pc
+ frame_offset = 0
+ if frame.function:
+ block = frame.GetFrameBlock()
+ block_range = block.range[frame.addr]
+ if block_range:
+ block_start_addr = block_range[0]
+ frame_offset = frame_pc - block_start_addr.load_addr
+ else:
+ frame_offset = frame_pc - frame.function.addr.load_addr
+ elif frame.symbol:
+ frame_offset = frame_pc - frame.symbol.addr.load_addr
+ out_file.write('%-3u %-32s 0x%16.16x %s' % (frame_idx, frame.module.file.basename, frame_pc, frame.name))
+ if frame_offset > 0:
+ out_file.write(' + %u' % (frame_offset))
+ line_entry = frame.line_entry
+ if line_entry:
+ if options.verbose:
+ # This will output the fullpath + line + column
+ out_file.write(' %s' % (line_entry))
+ else:
+ out_file.write(' %s:%u' % (line_entry.file.basename, line_entry.line))
+ column = line_entry.column
+ if column:
+ out_file.write(':%u' % (column))
+ out_file.write('\n')
+
+ out_file.write('\nBinary Images:\n')
+ for module in target.modules:
+ text_segment = module.section['__TEXT']
+ if text_segment:
+ text_segment_load_addr = text_segment.GetLoadAddress(target)
+ if text_segment_load_addr != lldb.LLDB_INVALID_ADDRESS:
+ text_segment_end_load_addr = text_segment_load_addr + text_segment.size
+ identifier = module.file.basename
+ module_version = '???'
+ module_version_array = module.GetVersion()
+ if module_version_array:
+ module_version = '.'.join(map(str,module_version_array))
+ out_file.write (' 0x%16.16x - 0x%16.16x %s (%s - ???) <%s> %s\n' % (text_segment_load_addr, text_segment_end_load_addr, identifier, module_version, module.GetUUIDString(), module.file.fullpath))
+ out_file.close()
+ else:
+ result.PutCString ("error: invalid target");
+
+
+def Symbolicate(debugger, command, result, dict):
+ try:
+ SymbolicateCrashLogs (shlex.split(command))
+ except:
+ result.PutCString ("error: python exception %s" % sys.exc_info()[0])
+
+def SymbolicateCrashLog(crash_log, options):
+ if crash_log.error:
+ print crash_log.error
+ return
+ if options.debug:
+ crash_log.dump()
+ if not crash_log.images:
+ print 'error: no images in crash log'
+ return
+
+ if options.dump_image_list:
+ print "Binary Images:"
+ for image in crash_log.images:
+ if options.verbose:
+ print image.debug_dump()
+ else:
+ print image
+
+ 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
+ if options.crashed_only:
+ for thread in crash_log.threads:
+ if thread.did_crash():
+ for ident in thread.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
+ else:
+ 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 not image in loaded_images:
+ err = image.add_module (target)
+ if err:
+ print err
+ else:
+ #print 'loaded %s' % image
+ loaded_images.append(image)
+
+ if crash_log.backtraces:
+ for thread in crash_log.backtraces:
+ thread.dump_symbolicated (crash_log, options)
+ print
+
+ for thread in crash_log.threads:
+ thread.dump_symbolicated (crash_log, options)
+ print
+
+
+def CreateSymbolicateCrashLogOptions(command_name, description, add_interactive_options):
+ usage = "usage: %prog [options] <FILE> [FILE ...]"
+ option_parser = optparse.OptionParser(description=description, prog='crashlog',usage=usage)
+ option_parser.add_option('--verbose' , '-v', action='store_true', dest='verbose', help='display verbose debug info', default=False)
+ option_parser.add_option('--debug' , '-g', action='store_true', dest='debug', help='display verbose debug logging', default=False)
+ option_parser.add_option('--load-all' , '-a', action='store_true', dest='load_all_images', help='load all executable images, not just the images found in the crashed stack frames', default=False)
+ option_parser.add_option('--images' , action='store_true', dest='dump_image_list', help='show image list', default=False)
+ option_parser.add_option('--debug-delay' , type='int', dest='debug_delay', metavar='NSEC', help='pause for NSEC seconds for debugger', default=0)
+ option_parser.add_option('--crashed-only' , '-c', action='store_true', dest='crashed_only', help='only symbolicate the crashed thread', default=False)
+ option_parser.add_option('--disasm-depth' , '-d', type='int', dest='disassemble_depth', help='set the depth in stack frames that should be disassembled (default is 1)', default=1)
+ option_parser.add_option('--disasm-all' , '-D', action='store_true', dest='disassemble_all_threads', help='enabled disassembly of frames on all threads (not just the crashed thread)', default=False)
+ option_parser.add_option('--disasm-before' , '-B', type='int', dest='disassemble_before', help='the number of instructions to disassemble before the frame PC', default=4)
+ option_parser.add_option('--disasm-after' , '-A', type='int', dest='disassemble_after', help='the number of instructions to disassemble after the frame PC', default=4)
+ option_parser.add_option('--source-context', '-C', type='int', metavar='NLINES', dest='source_context', help='show NLINES source lines of source context (default = 4)', default=4)
+ option_parser.add_option('--source-frames' , type='int', metavar='NFRAMES', dest='source_frames', help='show source for NFRAMES (default = 4)', default=4)
+ option_parser.add_option('--source-all' , action='store_true', dest='source_all', help='show source for all threads, not just the crashed thread', default=False)
+ if add_interactive_options:
+ option_parser.add_option('-i', '--interactive', action='store_true', help='parse all crash logs and enter interactive mode', default=False)
+ return option_parser
+
+def SymbolicateCrashLogs(command_args):
+ 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.'''
+ option_parser = CreateSymbolicateCrashLogOptions ('crashlog', description, True)
+ try:
+ (options, args) = option_parser.parse_args(command_args)
+ except:
+ return
+
+ if options.debug:
+ 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:
+ if options.interactive:
+ interactive_crashlogs(options, args)
+ else:
+ for crash_log_file in args:
+ crash_log = CrashLog(crash_log_file)
+ SymbolicateCrashLog (crash_log, options)
+if __name__ == '__main__':
+ # Create a new debugger instance
+ lldb.debugger = lldb.SBDebugger.Create()
+ SymbolicateCrashLogs (sys.argv[1:])
+ lldb.SBDebugger.Destroy (lldb.debugger)
+elif getattr(lldb, 'debugger', None):
+ lldb.debugger.HandleCommand('command script add -f lldb.macosx.crashlog.Symbolicate crashlog')
+ lldb.debugger.HandleCommand('command script add -f lldb.macosx.crashlog.save_crashlog save_crashlog')
+ print '"crashlog" and "save_crashlog" command installed, use the "--help" option for detailed help'
+
diff --git a/examples/python/delta.py b/examples/python/delta.py
new file mode 100755
index 0000000000000..e470de536d857
--- /dev/null
+++ b/examples/python/delta.py
@@ -0,0 +1,115 @@
+#!/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 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
+ 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/examples/python/diagnose_nsstring.py b/examples/python/diagnose_nsstring.py
new file mode 100644
index 0000000000000..aca5c7f220fc9
--- /dev/null
+++ b/examples/python/diagnose_nsstring.py
@@ -0,0 +1,171 @@
+# 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
+
+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 = "\
+struct $__lldb__notInlineMutable {\
+ char* buffer;\
+ signed long length;\
+ signed long capacity;\
+ unsigned int hasGap:1;\
+ unsigned int isFixedCapacity:1;\
+ unsigned int isExternalMutable:1;\
+ unsigned int capacityProvidedExternally:1;\n\
+#if __LP64__\n\
+ unsigned long desiredCapacity:60;\n\
+#else\n\
+ unsigned long desiredCapacity:28;\n\
+#endif\n\
+ void* contentsAllocator;\
+};\
+\
+struct $__lldb__CFString {\
+ void* _cfisa;\
+ uint8_t _cfinfo[4];\
+ uint32_t _rc;\
+ union {\
+ struct __inline1 {\
+ signed long length;\
+ } inline1;\
+ struct __notInlineImmutable1 {\
+ char* buffer;\
+ signed long length;\
+ void* contentsDeallocator;\
+ } notInlineImmutable1;\
+ struct __notInlineImmutable2 {\
+ char* buffer;\
+ void* contentsDeallocator;\
+ } notInlineImmutable2;\
+ struct $__lldb__notInlineMutable notInlineMutable;\
+ } variants;\
+};\
+"
+
+ 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")
+
+
+ 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)
+
+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.'
+
+__lldb_init_module(lldb.debugger,None)
+__lldb_init_module = None \ No newline at end of file
diff --git a/examples/python/diagnose_unwind.py b/examples/python/diagnose_unwind.py
new file mode 100644
index 0000000000000..e977c4ed1b0ff
--- /dev/null
+++ b/examples/python/diagnose_unwind.py
@@ -0,0 +1,270 @@
+# This implements the "diagnose-unwind" command, usually installed
+# in the debug session like
+# command script import lldb.diagnose
+# it is used when lldb's backtrace fails -- it collects and prints
+# information about the stack frames, and tries an alternate unwind
+# algorithm, that will help to understand why lldb's unwind algorithm
+# did not succeed.
+
+import optparse
+import lldb
+import re
+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()
+
+# 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()
+
+ 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)
+
+ 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:
+ 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
+
+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.
+ """
+
+ 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 = []
+
+ 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 ""
+ 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 "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)
+
+ 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)
+
+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
+
+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.'
diff --git a/examples/python/dict_utils.py b/examples/python/dict_utils.py
new file mode 100755
index 0000000000000..7dc5e7a8b56e3
--- /dev/null
+++ b/examples/python/dict_utils.py
@@ -0,0 +1,61 @@
+
+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):
+ """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):
+ """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):
+ """find the value given a key"""
+ if key in self:
+ return self[key]
+ return fail_value
+
+
+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':
+ if str in self:
+ v = self[v]
+ else:
+ 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 = "%#8.8x" % self.value
+ return s
+
+ def __repr__(self):
+ return self.__str__() \ No newline at end of file
diff --git a/examples/python/disasm-stress-test.py b/examples/python/disasm-stress-test.py
new file mode 100755
index 0000000000000..5aa354dc24cb1
--- /dev/null
+++ b/examples/python/disasm-stress-test.py
@@ -0,0 +1,168 @@
+#!/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/examples/python/disasm.py b/examples/python/disasm.py
new file mode 100755
index 0000000000000..732cf106b11d9
--- /dev/null
+++ b/examples/python/disasm.py
@@ -0,0 +1,119 @@
+#!/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/examples/python/file_extract.py b/examples/python/file_extract.py
new file mode 100755
index 0000000000000..3afc0c3c1a0b2
--- /dev/null
+++ b/examples/python/file_extract.py
@@ -0,0 +1,221 @@
+#! /usr/bin/env python
+
+import string
+import struct
+import sys
+
+class FileExtract:
+ '''Decode binary data from a file'''
+
+ 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':
+ self.byte_order = '>'
+ elif b == 'little':
+ self.byte_order = '<'
+ elif b == 'swap':
+ # swap what ever the current byte order is
+ self.byte_order = swap_unpack_char()
+ elif b == 'native':
+ self.byte_order = '='
+ elif b == '<' or b == '>' or b == '@' or b == '=':
+ self.byte_order = b
+ else:
+ print "error: invalid byte order specified: '%s'" % b
+
+ def is_in_memory(self):
+ return False
+
+ def seek(self, offset, whence = 0):
+ if self.file:
+ return self.file.seek(offset, whence)
+ raise ValueError
+
+ def tell(self):
+ if self.file:
+ return self.file.tell()
+ raise ValueError
+
+ def read_size (self, byte_size):
+ s = self.file.read(byte_size)
+ if len(s) != byte_size:
+ return None
+ return s
+
+ def push_offset_and_seek(self, offset):
+ '''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)
+ if s:
+ v, = struct.unpack(self.byte_order + 'b', s)
+ return v
+ else:
+ return fail_value
+
+ def get_uint8(self, fail_value=0):
+ '''Extract a single uint8_t from the binary file at the current file position, returns a single integer'''
+ s = self.read_size(1)
+ if s:
+ v, = struct.unpack(self.byte_order + 'B', s)
+ return v
+ else:
+ return fail_value
+
+ def get_sint16(self, fail_value=0):
+ '''Extract a single int16_t from the binary file at the current file position, returns a single integer'''
+ s = self.read_size(2)
+ if s:
+ v, = struct.unpack(self.byte_order + 'h', s)
+ return v
+ else:
+ return fail_value
+
+ def get_uint16(self, fail_value=0):
+ '''Extract a single uint16_t from the binary file at the current file position, returns a single integer'''
+ s = self.read_size(2)
+ if s:
+ v, = struct.unpack(self.byte_order + 'H', s)
+ return v
+ else:
+ return fail_value
+
+ def get_sint32(self, fail_value=0):
+ '''Extract a single int32_t from the binary file at the current file position, returns a single integer'''
+ s = self.read_size(4)
+ if s:
+ v, = struct.unpack(self.byte_order + 'i', s)
+ return v
+ else:
+ return fail_value
+
+ def get_uint32(self, fail_value=0):
+ '''Extract a single uint32_t from the binary file at the current file position, returns a single integer'''
+ s = self.read_size(4)
+ if s:
+ v, = struct.unpack(self.byte_order + 'I', s)
+ 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)
+ if s:
+ v, = struct.unpack(self.byte_order + 'q', s)
+ return v
+ else:
+ return fail_value
+
+ def get_uint64(self, fail_value=0):
+ '''Extract a single uint64_t from the binary file at the current file position, returns a single integer'''
+ s = self.read_size(8)
+ if s:
+ v, = struct.unpack(self.byte_order + 'Q', s)
+ return v
+ else:
+ return fail_value
+
+ 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:
+ cstr, = struct.unpack(self.byte_order + ("%i" % n) + 's', s)
+ # Strip trialing NULLs
+ cstr = string.strip(cstr, "\0")
+ if isprint_only_with_space_padding:
+ for c in cstr:
+ if c in string.printable or ord(c) == 0:
+ continue
+ return fail_value
+ return cstr
+ else:
+ return fail_value
+
+ def get_c_string(self):
+ '''Extract a single NULL terminated C string from the binary file at the current file position, returns a single C string'''
+ cstr = ''
+ byte = self.get_uint8()
+ while byte != 0:
+ cstr += "%c" % byte
+ byte = self.get_uint8()
+ return cstr
+
+ def get_n_sint8(self, n, fail_value=0):
+ '''Extract "n" int8_t integers from the binary file at the current file position, returns a list of integers'''
+ s = self.read_size(n)
+ if s:
+ return struct.unpack(self.byte_order + ("%u" % n) + 'b', s)
+ else:
+ return (fail_value,) * n
+
+ def get_n_uint8(self, n, fail_value=0):
+ '''Extract "n" uint8_t integers from the binary file at the current file position, returns a list of integers'''
+ s = self.read_size(n)
+ if s:
+ return struct.unpack(self.byte_order + ("%u" % n) + 'B', s)
+ else:
+ return (fail_value,) * n
+
+ 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)
+ if s:
+ return struct.unpack(self.byte_order + ("%u" % n) + 'h', s)
+ else:
+ return (fail_value,) * n
+
+ 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)
+ if s:
+ return struct.unpack(self.byte_order + ("%u" % n) + 'H', s)
+ else:
+ return (fail_value,) * n
+
+ 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)
+ if s:
+ return struct.unpack(self.byte_order + ("%u" % n) + 'i', s)
+ else:
+ return (fail_value,) * n
+
+ 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)
+ if s:
+ return struct.unpack(self.byte_order + ("%u" % n) + 'I', s)
+ else:
+ return (fail_value,) * n
+
+ 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)
+ if s:
+ return struct.unpack(self.byte_order + ("%u" % n) + 'q', s)
+ else:
+ return (fail_value,) * n
+
+ 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)
+ if s:
+ return struct.unpack(self.byte_order + ("%u" % n) + 'Q', s)
+ else:
+ return (fail_value,) * n
diff --git a/examples/python/gdb_disassemble.py b/examples/python/gdb_disassemble.py
new file mode 100755
index 0000000000000..d9a2f212fc9aa
--- /dev/null
+++ b/examples/python/gdb_disassemble.py
@@ -0,0 +1,24 @@
+import lldb
+
+def disassemble(debugger, command, result, dict):
+ if lldb.frame.function:
+ instructions = lldb.frame.function.instructions
+ start_addr = lldb.frame.function.addr.load_addr
+ name = lldb.frame.function.name
+ elif lldb.frame.symbol:
+ 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
+ comment = inst.comment
+ if comment:
+ 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' \ No newline at end of file
diff --git a/examples/python/gdbremote.py b/examples/python/gdbremote.py
new file mode 100755
index 0000000000000..4cbfdb2ba333a
--- /dev/null
+++ b/examples/python/gdbremote.py
@@ -0,0 +1,1362 @@
+#!/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 binascii
+import commands
+import json
+import math
+import optparse
+import os
+import re
+import shlex
+import string
+import sys
+import tempfile
+import xml.etree.ElementTree as ET
+
+#----------------------------------------------------------------------
+# Global variables
+#----------------------------------------------------------------------
+g_log_file = ''
+g_byte_order = 'little'
+g_number_regex = re.compile('^(0x[0-9a-fA-F]+|[0-9]+)')
+g_thread_id_regex = re.compile('^(-1|[0-9a-fA-F]+|0)')
+
+class TerminalColors:
+ '''Simple terminal colors class'''
+ def __init__(self, enabled = True):
+ # TODO: discover terminal type from "file" and disable if
+ # it can't handle the color codes
+ self.enabled = enabled
+
+ def reset(self):
+ '''Reset all terminal colors and formatting.'''
+ if self.enabled:
+ return "\x1b[0m";
+ return ''
+
+ def bold(self, on = True):
+ '''Enable or disable bold depending on the "on" parameter.'''
+ if self.enabled:
+ if on:
+ return "\x1b[1m";
+ else:
+ return "\x1b[22m";
+ return ''
+
+ def italics(self, on = True):
+ '''Enable or disable italics depending on the "on" parameter.'''
+ if self.enabled:
+ if on:
+ return "\x1b[3m";
+ else:
+ return "\x1b[23m";
+ return ''
+
+ def underline(self, on = True):
+ '''Enable or disable underline depending on the "on" parameter.'''
+ if self.enabled:
+ if on:
+ return "\x1b[4m";
+ else:
+ return "\x1b[24m";
+ return ''
+
+ def inverse(self, on = True):
+ '''Enable or disable inverse depending on the "on" parameter.'''
+ if self.enabled:
+ if on:
+ return "\x1b[7m";
+ else:
+ return "\x1b[27m";
+ return ''
+
+ def strike(self, on = True):
+ '''Enable or disable strike through depending on the "on" parameter.'''
+ if self.enabled:
+ if on:
+ return "\x1b[9m";
+ else:
+ return "\x1b[29m";
+ return ''
+
+ def black(self, fg = True):
+ '''Set the foreground or background color to black.
+ The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
+ if self.enabled:
+ if fg:
+ return "\x1b[30m";
+ else:
+ return "\x1b[40m";
+ return ''
+
+ def red(self, fg = True):
+ '''Set the foreground or background color to red.
+ The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
+ if self.enabled:
+ if fg:
+ return "\x1b[31m";
+ else:
+ return "\x1b[41m";
+ return ''
+
+ def green(self, fg = True):
+ '''Set the foreground or background color to green.
+ The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
+ if self.enabled:
+ if fg:
+ return "\x1b[32m";
+ else:
+ return "\x1b[42m";
+ return ''
+
+ def yellow(self, fg = True):
+ '''Set the foreground or background color to yellow.
+ The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
+ if self.enabled:
+ if fg:
+ return "\x1b[33m";
+ else:
+ return "\x1b[43m";
+ return ''
+
+ def blue(self, fg = True):
+ '''Set the foreground or background color to blue.
+ The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
+ if self.enabled:
+ if fg:
+ return "\x1b[34m";
+ else:
+ return "\x1b[44m";
+ return ''
+
+ def magenta(self, fg = True):
+ '''Set the foreground or background color to magenta.
+ The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
+ if self.enabled:
+ if fg:
+ return "\x1b[35m";
+ else:
+ return "\x1b[45m";
+ return ''
+
+ def cyan(self, fg = True):
+ '''Set the foreground or background color to cyan.
+ The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
+ if self.enabled:
+ if fg:
+ return "\x1b[36m";
+ else:
+ return "\x1b[46m";
+ return ''
+
+ def white(self, fg = True):
+ '''Set the foreground or background color to white.
+ The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
+ if self.enabled:
+ if fg:
+ return "\x1b[37m";
+ else:
+ return "\x1b[47m";
+ return ''
+
+ def default(self, fg = True):
+ '''Set the foreground or background color to the default.
+ The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
+ if self.enabled:
+ if fg:
+ return "\x1b[39m";
+ else:
+ return "\x1b[49m";
+ return ''
+
+
+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 g_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 g_log_file:
+ result.PutCString ('error: logging is already in progress with file "%s"' % g_log_file)
+ else:
+ args_len = len(args)
+ if args_len == 0:
+ g_log_file = tempfile.mktemp()
+ elif len(args) == 1:
+ g_log_file = args[0]
+
+ if g_log_file:
+ debugger.HandleCommand('log enable --threadsafe --timestamp --file "%s" gdb-remote packets' % g_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." % g_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 g_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', '--color', action='store_true', dest='color', help='add terminal colors', default=False)
+ parser.add_option('-c', '--sort-by-count', action='store_true', dest='sort_count', help='display verbose debug info', default=False)
+ parser.add_option('-s', '--symbolicate', action='store_true', dest='symbolicate', help='symbolicate addresses in log using current "lldb.target"', default=False)
+ try:
+ (options, args) = parser.parse_args(command_args)
+ except:
+ return
+ options.colors = TerminalColors(options.color)
+ options.symbolicator = None
+ if options.symbolicate:
+ if lldb.target:
+ import lldb.utils.symbolication
+ options.symbolicator = lldb.utils.symbolication.Symbolicator()
+ options.symbolicator.target = lldb.target
+ else:
+ print "error: can't symbolicate without a target"
+
+ if not g_log_file:
+ result.PutCString ('error: logging must have been previously enabled with a call to "stop_gdb_log"')
+ elif os.path.exists (g_log_file):
+ if len(args) == 0:
+ debugger.HandleCommand('log disable gdb-remote packets');
+ result.PutCString ("GDB packet logging disabled. Logged packets are in '%s'" % g_log_file)
+ parse_gdb_log_file (g_log_file, options)
+ else:
+ result.PutCString (usage)
+ else:
+ print 'error: the GDB packet log file "%s" does not exist' % g_log_file
+
+def is_hex_byte(str):
+ if len(str) == 2:
+ return str[0] in string.hexdigits and str[1] in string.hexdigits;
+ return False
+
+# global register info list
+g_register_infos = list()
+g_max_register_info_name_len = 0
+
+class RegisterInfo:
+ """Class that represents register information"""
+ def __init__(self, kvp):
+ self.info = dict()
+ for kv in kvp:
+ key = kv[0]
+ value = kv[1]
+ self.info[key] = value
+ def name(self):
+ '''Get the name of the register.'''
+ if self.info and 'name' in self.info:
+ return self.info['name']
+ return None
+
+ def bit_size(self):
+ '''Get the size in bits of the register.'''
+ if self.info and 'bitsize' in self.info:
+ return int(self.info['bitsize'])
+ return 0
+
+ def byte_size(self):
+ '''Get the size in bytes of the register.'''
+ return self.bit_size() / 8
+
+ def get_value_from_hex_string(self, hex_str):
+ '''Dump the register value given a native byte order encoded hex ASCII byte string.'''
+ encoding = self.info['encoding']
+ bit_size = self.bit_size()
+ packet = Packet(hex_str)
+ if encoding == 'uint':
+ uval = packet.get_hex_uint(g_byte_order)
+ if bit_size == 8:
+ return '0x%2.2x' % (uval)
+ elif bit_size == 16:
+ return '0x%4.4x' % (uval)
+ elif bit_size == 32:
+ return '0x%8.8x' % (uval)
+ elif bit_size == 64:
+ return '0x%16.16x' % (uval)
+ bytes = list();
+ uval = packet.get_hex_uint8()
+ while uval != None:
+ bytes.append(uval)
+ uval = packet.get_hex_uint8()
+ value_str = '0x'
+ if g_byte_order == 'little':
+ bytes.reverse()
+ for byte in bytes:
+ value_str += '%2.2x' % byte
+ return '%s' % (value_str)
+
+ def __str__(self):
+ '''Dump the register info key/value pairs'''
+ s = ''
+ for key in self.info.keys():
+ if s:
+ s += ', '
+ s += "%s=%s " % (key, self.info[key])
+ return s
+
+class Packet:
+ """Class that represents a packet that contains string data"""
+ def __init__(self, packet_str):
+ self.str = packet_str
+
+ def peek_char(self):
+ ch = 0
+ if self.str:
+ ch = self.str[0]
+ return ch
+
+ def get_char(self):
+ ch = 0
+ if self.str:
+ ch = self.str[0]
+ self.str = self.str[1:]
+ return ch
+
+ def skip_exact_string(self, s):
+ if self.str and self.str.startswith(s):
+ self.str = self.str[len(s):]
+ return True
+ else:
+ return False
+
+ def get_thread_id(self, fail_value = -1):
+ match = g_number_regex.match (self.str)
+ if match:
+ number_str = match.group(1)
+ self.str = self.str[len(number_str):]
+ return int(number_str, 0)
+ else:
+ return fail_value
+
+ def get_hex_uint8(self):
+ if self.str and len(self.str) >= 2 and self.str[0] in string.hexdigits and self.str[1] in string.hexdigits:
+ uval = int(self.str[0:2], 16)
+ self.str = self.str[2:]
+ return uval
+ return None
+
+ def get_hex_uint16(self, byte_order):
+ uval = 0
+ if byte_order == 'big':
+ uval |= self.get_hex_uint8() << 8
+ uval |= self.get_hex_uint8()
+ else:
+ uval |= self.get_hex_uint8()
+ uval |= self.get_hex_uint8() << 8
+ return uval
+
+ def get_hex_uint32(self, byte_order):
+ uval = 0
+ if byte_order == 'big':
+ uval |= self.get_hex_uint8() << 24
+ uval |= self.get_hex_uint8() << 16
+ uval |= self.get_hex_uint8() << 8
+ uval |= self.get_hex_uint8()
+ else:
+ uval |= self.get_hex_uint8()
+ uval |= self.get_hex_uint8() << 8
+ uval |= self.get_hex_uint8() << 16
+ uval |= self.get_hex_uint8() << 24
+ return uval
+
+ def get_hex_uint64(self, byte_order):
+ uval = 0
+ if byte_order == 'big':
+ uval |= self.get_hex_uint8() << 56
+ uval |= self.get_hex_uint8() << 48
+ uval |= self.get_hex_uint8() << 40
+ uval |= self.get_hex_uint8() << 32
+ uval |= self.get_hex_uint8() << 24
+ uval |= self.get_hex_uint8() << 16
+ uval |= self.get_hex_uint8() << 8
+ uval |= self.get_hex_uint8()
+ else:
+ uval |= self.get_hex_uint8()
+ uval |= self.get_hex_uint8() << 8
+ uval |= self.get_hex_uint8() << 16
+ uval |= self.get_hex_uint8() << 24
+ uval |= self.get_hex_uint8() << 32
+ uval |= self.get_hex_uint8() << 40
+ uval |= self.get_hex_uint8() << 48
+ uval |= self.get_hex_uint8() << 56
+ return uval
+
+ def get_number(self, fail_value=-1):
+ '''Get a number from the packet. The number must be in big endian format and should be parsed
+ according to its prefix (starts with "0x" means hex, starts with "0" means octal, starts with
+ [1-9] means decimal, etc)'''
+ match = g_number_regex.match (self.str)
+ if match:
+ number_str = match.group(1)
+ self.str = self.str[len(number_str):]
+ return int(number_str, 0)
+ else:
+ return fail_value
+
+
+ def get_hex_ascii_str(self, n=0):
+ hex_chars = self.get_hex_chars(n)
+ if hex_chars:
+ return binascii.unhexlify(hex_chars)
+ else:
+ return None
+
+ def get_hex_chars(self, n = 0):
+ str_len = len(self.str)
+ if n == 0:
+ # n was zero, so we need to determine all hex chars and
+ # stop when we hit the end of the string of a non-hex character
+ while n < str_len and self.str[n] in string.hexdigits:
+ n = n + 1
+ else:
+ if n > str_len:
+ return None # Not enough chars
+ # Verify all chars are hex if a length was specified
+ for i in range(n):
+ if self.str[i] not in string.hexdigits:
+ return None # Not all hex digits
+ if n == 0:
+ return None
+ hex_str = self.str[0:n]
+ self.str = self.str[n:]
+ return hex_str
+
+ def get_hex_uint(self, byte_order, n = 0):
+ if byte_order == 'big':
+ hex_str = self.get_hex_chars(n)
+ if hex_str == None:
+ return None
+ return int(hex_str, 16)
+ else:
+ uval = self.get_hex_uint8()
+ if uval == None:
+ return None
+ uval_result = 0
+ shift = 0
+ while uval != None:
+ uval_result |= (uval << shift)
+ shift += 8
+ uval = self.get_hex_uint8()
+ return uval_result
+
+ def get_key_value_pairs(self):
+ kvp = list()
+ if ';' in self.str:
+ key_value_pairs = string.split(self.str, ';')
+ for key_value_pair in key_value_pairs:
+ if len(key_value_pair):
+ kvp.append(string.split(key_value_pair, ':'))
+ return kvp
+
+ def split(self, ch):
+ return string.split(self.str, ch)
+
+ def split_hex(self, ch, byte_order):
+ hex_values = list()
+ strings = string.split(self.str, ch)
+ for str in strings:
+ hex_values.append(Packet(str).get_hex_uint(byte_order))
+ return hex_values
+
+ def __str__(self):
+ return self.str
+
+ def __len__(self):
+ return len(self.str)
+
+g_thread_suffix_regex = re.compile(';thread:([0-9a-fA-F]+);')
+def get_thread_from_thread_suffix(str):
+ if str:
+ match = g_thread_suffix_regex.match (str)
+ if match:
+ return int(match.group(1), 16)
+ return None
+
+def cmd_qThreadStopInfo(options, cmd, args):
+ packet = Packet(args)
+ tid = packet.get_hex_uint('big')
+ print "get_thread_stop_info (tid = 0x%x)" % (tid)
+
+def cmd_stop_reply(options, cmd, args):
+ print "get_last_stop_info()"
+ return False
+
+def rsp_stop_reply(options, cmd, cmd_args, rsp):
+ global g_byte_order
+ packet = Packet(rsp)
+ stop_type = packet.get_char()
+ if stop_type == 'T' or stop_type == 'S':
+ signo = packet.get_hex_uint8()
+ key_value_pairs = packet.get_key_value_pairs()
+ for key_value_pair in key_value_pairs:
+ key = key_value_pair[0]
+ if is_hex_byte(key):
+ reg_num = Packet(key).get_hex_uint8()
+ if reg_num < len(g_register_infos):
+ reg_info = g_register_infos[reg_num]
+ key_value_pair[0] = reg_info.name()
+ key_value_pair[1] = reg_info.get_value_from_hex_string (key_value_pair[1])
+ elif key == 'jthreads' or key == 'jstopinfo':
+ key_value_pair[1] = binascii.unhexlify(key_value_pair[1])
+ key_value_pairs.insert(0, ['signal', signo])
+ print 'stop_reply():'
+ dump_key_value_pairs (key_value_pairs)
+ elif stop_type == 'W':
+ exit_status = packet.get_hex_uint8()
+ print 'stop_reply(): exit (status=%i)' % exit_status
+ elif stop_type == 'O':
+ print 'stop_reply(): stdout = "%s"' % packet.str
+
+
+def cmd_unknown_packet(options, cmd, args):
+ if args:
+ print "cmd: %s, args: %s", cmd, args
+ else:
+ print "cmd: %s", cmd
+ return False
+
+def cmd_qSymbol(options, cmd, args):
+ if args == ':':
+ print 'ready to serve symbols'
+ else:
+ packet = Packet(args)
+ symbol_addr = packet.get_hex_uint('big')
+ if symbol_addr is None:
+ if packet.skip_exact_string(':'):
+ symbol_name = packet.get_hex_ascii_str()
+ print 'lookup_symbol("%s") -> symbol not available yet' % (symbol_name)
+ else:
+ print 'error: bad command format'
+ else:
+ if packet.skip_exact_string(':'):
+ symbol_name = packet.get_hex_ascii_str()
+ print 'lookup_symbol("%s") -> 0x%x' % (symbol_name, symbol_addr)
+ else:
+ print 'error: bad command format'
+
+def rsp_qSymbol(options, cmd, cmd_args, rsp):
+ if len(rsp) == 0:
+ print "Unsupported"
+ else:
+ if rsp == "OK":
+ print "No more symbols to lookup"
+ else:
+ packet = Packet(rsp)
+ if packet.skip_exact_string("qSymbol:"):
+ symbol_name = packet.get_hex_ascii_str()
+ print 'lookup_symbol("%s")' % (symbol_name)
+ else:
+ print 'error: response string should start with "qSymbol:": respnse is "%s"' % (rsp)
+
+def cmd_qXfer(options, cmd, args):
+ # $qXfer:features:read:target.xml:0,1ffff#14
+ print "read target special data %s" % (args)
+ return True
+
+def rsp_qXfer(options, cmd, cmd_args, rsp):
+ data = string.split(cmd_args, ':')
+ if data[0] == 'features':
+ if data[1] == 'read':
+ filename, extension = os.path.splitext(data[2])
+ if extension == '.xml':
+ response = Packet(rsp)
+ xml_string = response.get_hex_ascii_str()
+ ch = xml_string[0]
+ if ch == 'l':
+ xml_string = xml_string[1:]
+ xml_root = ET.fromstring(xml_string)
+ for reg_element in xml_root.findall("./feature/reg"):
+ if not 'value_regnums' in reg_element.attrib:
+ reg_info = RegisterInfo([])
+ if 'name' in reg_element.attrib:
+ reg_info.info['name'] = reg_element.attrib['name']
+ else:
+ reg_info.info['name'] = 'unspecified'
+ if 'encoding' in reg_element.attrib:
+ reg_info.info['encoding'] = reg_element.attrib['encoding']
+ else:
+ reg_info.info['encoding'] = 'uint'
+ if 'offset' in reg_element.attrib:
+ reg_info.info['offset'] = reg_element.attrib['offset']
+ if 'bitsize' in reg_element.attrib:
+ reg_info.info['bitsize'] = reg_element.attrib['bitsize']
+ g_register_infos.append(reg_info)
+ print 'XML for "%s":' % (data[2])
+ ET.dump(xml_root)
+
+def cmd_A(options, cmd, args):
+ print 'launch process:'
+ packet = Packet(args)
+ while 1:
+ arg_len = packet.get_number()
+ if arg_len == -1:
+ break
+ if not packet.skip_exact_string(','):
+ break
+ arg_idx = packet.get_number()
+ if arg_idx == -1:
+ break
+ if not packet.skip_exact_string(','):
+ break;
+ arg_value = packet.get_hex_ascii_str(arg_len)
+ print 'argv[%u] = "%s"' % (arg_idx, arg_value)
+
+def cmd_qC(options, cmd, args):
+ print "query_current_thread_id()"
+
+def rsp_qC(options, cmd, cmd_args, rsp):
+ packet = Packet(rsp)
+ if packet.skip_exact_string("QC"):
+ tid = packet.get_thread_id()
+ print "current_thread_id = %#x" % (tid)
+ else:
+ print "current_thread_id = old thread ID"
+
+def cmd_query_packet(options, cmd, args):
+ if args:
+ print "%s%s" % (cmd, args)
+ else:
+ print "%s" % (cmd)
+ return False
+
+def rsp_ok_error(rsp):
+ print "rsp: ", rsp
+
+def rsp_ok_means_supported(options, cmd, cmd_args, rsp):
+ if rsp == 'OK':
+ print "%s%s is supported" % (cmd, cmd_args)
+ elif rsp == '':
+ print "%s%s is not supported" % (cmd, cmd_args)
+ else:
+ print "%s%s -> %s" % (cmd, cmd_args, rsp)
+
+def rsp_ok_means_success(options, cmd, cmd_args, rsp):
+ if rsp == 'OK':
+ print "success"
+ elif rsp == '':
+ print "%s%s is not supported" % (cmd, cmd_args)
+ else:
+ print "%s%s -> %s" % (cmd, cmd_args, rsp)
+
+def dump_key_value_pairs(key_value_pairs):
+ max_key_len = 0
+ for key_value_pair in key_value_pairs:
+ key_len = len(key_value_pair[0])
+ if max_key_len < key_len:
+ max_key_len = key_len
+ for key_value_pair in key_value_pairs:
+ key = key_value_pair[0]
+ value = key_value_pair[1]
+ print "%*s = %s" % (max_key_len, key, value)
+
+def rsp_dump_key_value_pairs(options, cmd, cmd_args, rsp):
+ if rsp:
+ print '%s response:' % (cmd)
+ packet = Packet(rsp)
+ key_value_pairs = packet.get_key_value_pairs()
+ dump_key_value_pairs(key_value_pairs)
+ else:
+ print "not supported"
+
+def cmd_c(options, cmd, args):
+ print "continue()"
+ return False
+
+def cmd_s(options, cmd, args):
+ print "step()"
+ return False
+
+def cmd_vCont(options, cmd, args):
+ if args == '?':
+ print "%s: get supported extended continue modes" % (cmd)
+ else:
+ got_other_threads = 0
+ s = ''
+ for thread_action in string.split(args[1:], ';'):
+ (short_action, thread) = string.split(thread_action, ':')
+ tid = int(thread, 16)
+ if short_action == 'c':
+ action = 'continue'
+ elif short_action == 's':
+ action = 'step'
+ elif short_action[0] == 'C':
+ action = 'continue with signal 0x%s' % (short_action[1:])
+ elif short_action == 'S':
+ action = 'step with signal 0x%s' % (short_action[1:])
+ else:
+ action = short_action
+ if s:
+ s += ', '
+ if tid == -1:
+ got_other_threads = 1
+ s += 'other-threads:'
+ else:
+ s += 'thread 0x%4.4x: %s' % (tid, action)
+ if got_other_threads:
+ print "extended_continue (%s)" % (s)
+ else:
+ print "extended_continue (%s, other-threads: suspend)" % (s)
+ return False
+
+def rsp_vCont(options, cmd, cmd_args, rsp):
+ if cmd_args == '?':
+ # Skip the leading 'vCont;'
+ rsp = rsp[6:]
+ modes = string.split(rsp, ';')
+ s = "%s: supported extended continue modes include: " % (cmd)
+
+ for i, mode in enumerate(modes):
+ if i:
+ s += ', '
+ if mode == 'c':
+ s += 'continue'
+ elif mode == 'C':
+ s += 'continue with signal'
+ elif mode == 's':
+ s += 'step'
+ elif mode == 'S':
+ s += 'step with signal'
+ else:
+ s += 'unrecognized vCont mode: ', mode
+ print s
+ elif rsp:
+ if rsp[0] == 'T' or rsp[0] == 'S' or rsp[0] == 'W' or rsp[0] == 'X':
+ rsp_stop_reply (options, cmd, cmd_args, rsp)
+ return
+ if rsp[0] == 'O':
+ print "stdout: %s" % (rsp)
+ return
+ else:
+ print "not supported (cmd = '%s', args = '%s', rsp = '%s')" % (cmd, cmd_args, rsp)
+
+def cmd_vAttach(options, cmd, args):
+ (extra_command, args) = string.split(args, ';')
+ if extra_command:
+ print "%s%s(%s)" % (cmd, extra_command, args)
+ else:
+ print "attach(pid = %u)" % int(args, 16)
+ return False
+
+
+def cmd_qRegisterInfo(options, cmd, args):
+ print 'query_register_info(reg_num=%i)' % (int(args, 16))
+ return False
+
+def rsp_qRegisterInfo(options, cmd, cmd_args, rsp):
+ global g_max_register_info_name_len
+ print 'query_register_info(reg_num=%i):' % (int(cmd_args, 16)),
+ if len(rsp) == 3 and rsp[0] == 'E':
+ g_max_register_info_name_len = 0
+ for reg_info in g_register_infos:
+ name_len = len(reg_info.name())
+ if g_max_register_info_name_len < name_len:
+ g_max_register_info_name_len = name_len
+ print' DONE'
+ else:
+ packet = Packet(rsp)
+ reg_info = RegisterInfo(packet.get_key_value_pairs())
+ g_register_infos.append(reg_info)
+ print reg_info
+ return False
+
+def cmd_qThreadInfo(options, cmd, args):
+ if cmd == 'qfThreadInfo':
+ query_type = 'first'
+ else:
+ query_type = 'subsequent'
+ print 'get_current_thread_list(type=%s)' % (query_type)
+ return False
+
+def rsp_qThreadInfo(options, cmd, cmd_args, rsp):
+ packet = Packet(rsp)
+ response_type = packet.get_char()
+ if response_type == 'm':
+ tids = packet.split_hex(';', 'big')
+ for i, tid in enumerate(tids):
+ if i:
+ print ',',
+ print '0x%x' % (tid),
+ print
+ elif response_type == 'l':
+ print 'END'
+
+def rsp_hex_big_endian(options, cmd, cmd_args, rsp):
+ packet = Packet(rsp)
+ uval = packet.get_hex_uint('big')
+ print '%s: 0x%x' % (cmd, uval)
+
+def cmd_read_mem_bin(options, cmd, args):
+ # x0x7fff5fc39200,0x200
+ packet = Packet(args)
+ addr = packet.get_number()
+ comma = packet.get_char()
+ size = packet.get_number()
+ print 'binary_read_memory (addr = 0x%16.16x, size = %u)' % (addr, size)
+ return False
+
+def rsp_mem_bin_bytes(options, cmd, cmd_args, rsp):
+ packet = Packet(cmd_args)
+ addr = packet.get_number()
+ comma = packet.get_char()
+ size = packet.get_number()
+ print 'memory:'
+ if size > 0:
+ dump_hex_memory_buffer (addr, rsp)
+
+def cmd_read_memory(options, cmd, args):
+ packet = Packet(args)
+ addr = packet.get_hex_uint('big')
+ comma = packet.get_char()
+ size = packet.get_hex_uint('big')
+ print 'read_memory (addr = 0x%16.16x, size = %u)' % (addr, size)
+ return False
+
+def dump_hex_memory_buffer(addr, hex_byte_str):
+ packet = Packet(hex_byte_str)
+ idx = 0
+ ascii = ''
+ uval = packet.get_hex_uint8()
+ while uval != None:
+ if ((idx % 16) == 0):
+ if ascii:
+ print ' ', ascii
+ ascii = ''
+ print '0x%x:' % (addr + idx),
+ print '%2.2x' % (uval),
+ if 0x20 <= uval and uval < 0x7f:
+ ascii += '%c' % uval
+ else:
+ ascii += '.'
+ uval = packet.get_hex_uint8()
+ idx = idx + 1
+ if ascii:
+ print ' ', ascii
+ ascii = ''
+
+def cmd_write_memory(options, cmd, args):
+ packet = Packet(args)
+ addr = packet.get_hex_uint('big')
+ if packet.get_char() != ',':
+ print 'error: invalid write memory command (missing comma after address)'
+ return
+ size = packet.get_hex_uint('big')
+ if packet.get_char() != ':':
+ print 'error: invalid write memory command (missing colon after size)'
+ return
+ print 'write_memory (addr = 0x%16.16x, size = %u, data:' % (addr, size)
+ dump_hex_memory_buffer (addr, packet.str)
+ return False
+
+def cmd_alloc_memory(options, cmd, args):
+ packet = Packet(args)
+ byte_size = packet.get_hex_uint('big')
+ if packet.get_char() != ',':
+ print 'error: invalid allocate memory command (missing comma after address)'
+ return
+ print 'allocate_memory (byte-size = %u (0x%x), permissions = %s)' % (byte_size, byte_size, packet.str)
+ return False
+
+def rsp_alloc_memory(options, cmd, cmd_args, rsp):
+ packet = Packet(rsp)
+ addr = packet.get_hex_uint('big')
+ print 'addr = 0x%x' % addr
+
+def cmd_dealloc_memory(options, cmd, args):
+ packet = Packet(args)
+ addr = packet.get_hex_uint('big')
+ if packet.get_char() != ',':
+ print 'error: invalid allocate memory command (missing comma after address)'
+ else:
+ print 'deallocate_memory (addr = 0x%x, permissions = %s)' % (addr, packet.str)
+ return False
+def rsp_memory_bytes(options, cmd, cmd_args, rsp):
+ addr = Packet(cmd_args).get_hex_uint('big')
+ dump_hex_memory_buffer (addr, rsp)
+
+def get_register_name_equal_value(options, reg_num, hex_value_str):
+ if reg_num < len(g_register_infos):
+ reg_info = g_register_infos[reg_num]
+ value_str = reg_info.get_value_from_hex_string (hex_value_str)
+ s = reg_info.name() + ' = '
+ if options.symbolicator:
+ symbolicated_addresses = options.symbolicator.symbolicate (int(value_str, 0))
+ if symbolicated_addresses:
+ s += options.colors.magenta()
+ s += '%s' % symbolicated_addresses[0]
+ s += options.colors.reset()
+ return s
+ s += value_str
+ return s
+ else:
+ reg_value = Packet(hex_value_str).get_hex_uint(g_byte_order)
+ return 'reg(%u) = 0x%x' % (reg_num, reg_value)
+
+def cmd_read_one_reg(options, cmd, args):
+ packet = Packet(args)
+ reg_num = packet.get_hex_uint('big')
+ tid = get_thread_from_thread_suffix (packet.str)
+ name = None
+ if reg_num < len(g_register_infos):
+ name = g_register_infos[reg_num].name ()
+ if packet.str:
+ packet.get_char() # skip ;
+ thread_info = packet.get_key_value_pairs()
+ tid = int(thread_info[0][1], 16)
+ s = 'read_register (reg_num=%u' % reg_num
+ if name:
+ s += ' (%s)' % (name)
+ if tid != None:
+ s += ', tid = 0x%4.4x' % (tid)
+ s += ')'
+ print s
+ return False
+
+def rsp_read_one_reg(options, cmd, cmd_args, rsp):
+ packet = Packet(cmd_args)
+ reg_num = packet.get_hex_uint('big')
+ print get_register_name_equal_value (options, reg_num, rsp)
+
+def cmd_write_one_reg(options, cmd, args):
+ packet = Packet(args)
+ reg_num = packet.get_hex_uint('big')
+ if packet.get_char() != '=':
+ print 'error: invalid register write packet'
+ else:
+ name = None
+ hex_value_str = packet.get_hex_chars()
+ tid = get_thread_from_thread_suffix (packet.str)
+ s = 'write_register (reg_num=%u' % reg_num
+ if name:
+ s += ' (%s)' % (name)
+ s += ', value = '
+ s += get_register_name_equal_value(options, reg_num, hex_value_str)
+ if tid != None:
+ s += ', tid = 0x%4.4x' % (tid)
+ s += ')'
+ print s
+ return False
+
+def dump_all_regs(packet):
+ for reg_info in g_register_infos:
+ nibble_size = reg_info.bit_size() / 4
+ hex_value_str = packet.get_hex_chars(nibble_size)
+ if hex_value_str != None:
+ value = reg_info.get_value_from_hex_string (hex_value_str)
+ print '%*s = %s' % (g_max_register_info_name_len, reg_info.name(), value)
+ else:
+ return
+
+def cmd_read_all_regs(cmd, cmd_args):
+ packet = Packet(cmd_args)
+ packet.get_char() # toss the 'g' command character
+ tid = get_thread_from_thread_suffix (packet.str)
+ if tid != None:
+ print 'read_all_register(thread = 0x%4.4x)' % tid
+ else:
+ print 'read_all_register()'
+ return False
+
+def rsp_read_all_regs(options, cmd, cmd_args, rsp):
+ packet = Packet(rsp)
+ dump_all_regs (packet)
+
+def cmd_write_all_regs(options, cmd, args):
+ packet = Packet(args)
+ print 'write_all_registers()'
+ dump_all_regs (packet)
+ return False
+
+g_bp_types = [ "software_bp", "hardware_bp", "write_wp", "read_wp", "access_wp" ]
+
+def cmd_bp(options, cmd, args):
+ if cmd == 'Z':
+ s = 'set_'
+ else:
+ s = 'clear_'
+ packet = Packet (args)
+ bp_type = packet.get_hex_uint('big')
+ packet.get_char() # Skip ,
+ bp_addr = packet.get_hex_uint('big')
+ packet.get_char() # Skip ,
+ bp_size = packet.get_hex_uint('big')
+ s += g_bp_types[bp_type]
+ s += " (addr = 0x%x, size = %u)" % (bp_addr, bp_size)
+ print s
+ return False
+
+def cmd_mem_rgn_info(options, cmd, args):
+ packet = Packet(args)
+ packet.get_char() # skip ':' character
+ addr = packet.get_hex_uint('big')
+ print 'get_memory_region_info (addr=0x%x)' % (addr)
+ return False
+
+def cmd_kill(options, cmd, args):
+ print 'kill_process()'
+ return False
+
+def cmd_jThreadsInfo(options, cmd, args):
+ print 'jThreadsInfo()'
+ return False
+
+def cmd_jGetLoadedDynamicLibrariesInfos(options, cmd, args):
+ print 'jGetLoadedDynamicLibrariesInfos()'
+ return False
+
+def decode_packet(s, start_index = 0):
+ #print '\ndecode_packet("%s")' % (s[start_index:])
+ index = s.find('}', start_index)
+ have_escapes = index != -1
+ if have_escapes:
+ normal_s = s[start_index:index]
+ else:
+ normal_s = s[start_index:]
+ #print 'normal_s = "%s"' % (normal_s)
+ if have_escapes:
+ escape_char = '%c' % (ord(s[index+1]) ^ 0x20)
+ #print 'escape_char for "%s" = %c' % (s[index:index+2], escape_char)
+ return normal_s + escape_char + decode_packet(s, index+2)
+ else:
+ return normal_s
+
+def rsp_json(options, cmd, cmd_args, rsp):
+ print '%s() reply:' % (cmd)
+ json_tree = json.loads(rsp)
+ print json.dumps(json_tree, indent=4, separators=(',', ': '))
+
+
+def rsp_jGetLoadedDynamicLibrariesInfos(options, cmd, cmd_args, rsp):
+ if cmd_args:
+ rsp_json(options, cmd, cmd_args, rsp)
+ else:
+ rsp_ok_means_supported(options, cmd, cmd_args, rsp)
+
+gdb_remote_commands = {
+ '\\?' : { 'cmd' : cmd_stop_reply , 'rsp' : rsp_stop_reply , 'name' : "stop reply pacpket"},
+ 'qThreadStopInfo' : { 'cmd' : cmd_qThreadStopInfo , 'rsp' : rsp_stop_reply , 'name' : "stop reply pacpket"},
+ 'QStartNoAckMode' : { 'cmd' : cmd_query_packet , 'rsp' : rsp_ok_means_supported , 'name' : "query if no ack mode is supported"},
+ 'QThreadSuffixSupported' : { 'cmd' : cmd_query_packet , 'rsp' : rsp_ok_means_supported , 'name' : "query if thread suffix is supported" },
+ 'QListThreadsInStopReply' : { 'cmd' : cmd_query_packet , 'rsp' : rsp_ok_means_supported , 'name' : "query if threads in stop reply packets are supported" },
+ 'QSetDetachOnError' : { 'cmd' : cmd_query_packet , 'rsp' : rsp_ok_means_success , 'name' : "set if we should detach on error" },
+ 'QSetDisableASLR' : { 'cmd' : cmd_query_packet , 'rsp' : rsp_ok_means_success , 'name' : "set if we should disable ASLR" },
+ 'qLaunchSuccess' : { 'cmd' : cmd_query_packet , 'rsp' : rsp_ok_means_success , 'name' : "check on launch success for the A packet" },
+ 'A' : { 'cmd' : cmd_A , 'rsp' : rsp_ok_means_success , 'name' : "launch process" },
+ 'QLaunchArch' : { 'cmd' : cmd_query_packet , 'rsp' : rsp_ok_means_supported , 'name' : "set if we should disable ASLR" },
+ 'qVAttachOrWaitSupported' : { 'cmd' : cmd_query_packet , 'rsp' : rsp_ok_means_supported , 'name' : "set the launch architecture" },
+ 'qHostInfo' : { 'cmd' : cmd_query_packet , 'rsp' : rsp_dump_key_value_pairs, 'name' : "get host information" },
+ 'qC' : { 'cmd' : cmd_qC , 'rsp' : rsp_qC , 'name' : "return the current thread ID" },
+ 'vCont' : { 'cmd' : cmd_vCont , 'rsp' : rsp_vCont , 'name' : "extended continue command" },
+ 'vAttach' : { 'cmd' : cmd_vAttach , 'rsp' : rsp_stop_reply , 'name' : "attach to process" },
+ 'c' : { 'cmd' : cmd_c , 'rsp' : rsp_stop_reply , 'name' : "continue" },
+ 's' : { 'cmd' : cmd_s , 'rsp' : rsp_stop_reply , 'name' : "step" },
+ 'qRegisterInfo' : { 'cmd' : cmd_qRegisterInfo , 'rsp' : rsp_qRegisterInfo , 'name' : "query register info" },
+ 'qfThreadInfo' : { 'cmd' : cmd_qThreadInfo , 'rsp' : rsp_qThreadInfo , 'name' : "get current thread list" },
+ 'qsThreadInfo' : { 'cmd' : cmd_qThreadInfo , 'rsp' : rsp_qThreadInfo , 'name' : "get current thread list" },
+ 'qShlibInfoAddr' : { 'cmd' : cmd_query_packet , 'rsp' : rsp_hex_big_endian , 'name' : "get shared library info address" },
+ 'qMemoryRegionInfo' : { 'cmd' : cmd_mem_rgn_info , 'rsp' : rsp_dump_key_value_pairs, 'name' : "get memory region information" },
+ 'qProcessInfo' : { 'cmd' : cmd_query_packet , 'rsp' : rsp_dump_key_value_pairs, 'name' : "get process info" },
+ 'qSupported' : { 'cmd' : cmd_query_packet , 'rsp' : rsp_ok_means_supported , 'name' : "query supported" },
+ 'qXfer:' : { 'cmd' : cmd_qXfer , 'rsp' : rsp_qXfer , 'name' : "qXfer" },
+ 'qSymbol:' : { 'cmd' : cmd_qSymbol , 'rsp' : rsp_qSymbol , 'name' : "qSymbol" },
+ 'x' : { 'cmd' : cmd_read_mem_bin , 'rsp' : rsp_mem_bin_bytes , 'name' : "read memory binary" },
+ 'X' : { 'cmd' : cmd_write_memory , 'rsp' : rsp_ok_means_success , 'name' : "write memory binary" },
+ 'm' : { 'cmd' : cmd_read_memory , 'rsp' : rsp_memory_bytes , 'name' : "read memory" },
+ 'M' : { 'cmd' : cmd_write_memory , 'rsp' : rsp_ok_means_success , 'name' : "write memory" },
+ '_M' : { 'cmd' : cmd_alloc_memory , 'rsp' : rsp_alloc_memory , 'name' : "allocate memory" },
+ '_m' : { 'cmd' : cmd_dealloc_memory , 'rsp' : rsp_ok_means_success , 'name' : "deallocate memory" },
+ 'p' : { 'cmd' : cmd_read_one_reg , 'rsp' : rsp_read_one_reg , 'name' : "read single register" },
+ 'P' : { 'cmd' : cmd_write_one_reg , 'rsp' : rsp_ok_means_success , 'name' : "write single register" },
+ 'g' : { 'cmd' : cmd_read_all_regs , 'rsp' : rsp_read_all_regs , 'name' : "read all registers" },
+ 'G' : { 'cmd' : cmd_write_all_regs , 'rsp' : rsp_ok_means_success , 'name' : "write all registers" },
+ 'z' : { 'cmd' : cmd_bp , 'rsp' : rsp_ok_means_success , 'name' : "clear breakpoint or watchpoint" },
+ 'Z' : { 'cmd' : cmd_bp , 'rsp' : rsp_ok_means_success , 'name' : "set breakpoint or watchpoint" },
+ 'k' : { 'cmd' : cmd_kill , 'rsp' : rsp_stop_reply , 'name' : "kill process" },
+ 'jThreadsInfo' : { 'cmd' : cmd_jThreadsInfo , 'rsp' : rsp_json , 'name' : "JSON get all threads info" },
+ 'jGetLoadedDynamicLibrariesInfos:' : { 'cmd' : cmd_jGetLoadedDynamicLibrariesInfos, 'rsp' : rsp_jGetLoadedDynamicLibrariesInfos, 'name' : 'JSON get loaded dynamic libraries' },
+}
+
+def calculate_mean_and_standard_deviation(floats):
+ sum = 0.0
+ count = len(floats)
+ if count == 0:
+ return (0.0, 0.0)
+ for f in floats:
+ sum += f
+ mean = sum / count
+ accum = 0.0
+ for f in floats:
+ delta = f - mean
+ accum += delta * delta
+
+ std_dev = math.sqrt(accum / (count-1));
+ return (mean, std_dev)
+
+def parse_gdb_log_file(path, options):
+ f = open(path)
+ parse_gdb_log(f, options)
+ f.close()
+
+def parse_gdb_log(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 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
+ 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]')
+ packet_transmit_name_regex = re.compile('(?P<direction>send|read) packet: (?P<packet>.*)')
+ packet_contents_name_regex = re.compile('\$([^#]+)#[0-9a-fA-F]{2}')
+ packet_checksum_regex = re.compile('.*#[0-9a-fA-F]{2}$')
+ packet_names_regex_str = '(' + '|'.join(gdb_remote_commands.keys()) + ')(.*)';
+ packet_names_regex = re.compile(packet_names_regex_str);
+
+ base_time = 0.0
+ last_time = 0.0
+ packet_send_time = 0.0
+ packet_total_times = {}
+ packet_times = []
+ packet_count = {}
+ lines = file.read().splitlines()
+ last_command = None
+ last_command_args = None
+ last_command_packet = None
+ hide_next_response = False
+ num_lines = len(lines)
+ skip_count = 0
+ for (line_index, line) in enumerate(lines):
+ # See if we need to skip any lines
+ if skip_count > 0:
+ skip_count -= 1
+ continue
+ m = packet_transmit_name_regex.search(line)
+ is_command = False
+ direction = None
+ if m:
+ direction = m.group('direction')
+ is_command = direction == 'send'
+ packet = m.group('packet')
+ sys.stdout.write(options.colors.green())
+ if not options.quiet and not hide_next_response:
+ print '# ', line
+ sys.stdout.write(options.colors.reset())
+
+ #print 'direction = "%s", packet = "%s"' % (direction, packet)
+
+ if packet[0] == '+':
+ if is_command:
+ print '-->',
+ else:
+ print '<--',
+ if not options.quiet: print 'ACK'
+ continue
+ elif packet[0] == '-':
+ if is_command:
+ print '-->',
+ else:
+ print '<--',
+ if not options.quiet: print 'NACK'
+ continue
+ elif packet[0] == '$':
+ m = packet_contents_name_regex.match(packet)
+ if not m and packet[0] == '$':
+ multiline_packet = packet
+ idx = line_index + 1
+ while idx < num_lines:
+ if not options.quiet and not hide_next_response:
+ print '# ', lines[idx]
+ multiline_packet += lines[idx]
+ m = packet_contents_name_regex.match(multiline_packet)
+ if m:
+ packet = multiline_packet
+ skip_count = idx - line_index
+ break
+ else:
+ idx += 1
+ if m:
+ if is_command:
+ print '-->',
+ else:
+ print '<--',
+ contents = decode_packet(m.group(1))
+ if is_command:
+ hide_next_response = False
+ m = packet_names_regex.match (contents)
+ if m:
+ last_command = m.group(1)
+ if last_command == '?':
+ last_command = '\\?'
+ packet_name = last_command
+ last_command_args = m.group(2)
+ last_command_packet = contents
+ hide_next_response = gdb_remote_commands[last_command]['cmd'](options, last_command, last_command_args)
+ else:
+ packet_match = packet_name_regex.match (contents)
+ if packet_match:
+ packet_name = packet_match.group(1)
+ for tricky_cmd in tricky_commands:
+ if packet_name.find (tricky_cmd) == 0:
+ packet_name = tricky_cmd
+ else:
+ packet_name = contents
+ last_command = None
+ last_command_args = None
+ last_command_packet = None
+ elif last_command:
+ gdb_remote_commands[last_command]['rsp'](options, last_command, last_command_args, contents)
+ else:
+ print 'error: invalid packet: "', packet, '"'
+ else:
+ print '???'
+ else:
+ print '## ', line
+ match = timestamp_regex.match (line)
+ if match:
+ curr_time = float (match.group(2))
+ if last_time and not is_command:
+ delta = curr_time - last_time
+ packet_times.append(delta)
+ delta = 0.0
+ if base_time:
+ delta = curr_time - last_time
+ else:
+ base_time = curr_time
+
+ if is_command:
+ packet_send_time = curr_time
+ 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
+ (average, std_dev) = calculate_mean_and_standard_deviation(packet_times)
+ if average and std_dev:
+ print '%u packets with average packet time of %f and standard deviation of %f' % (len(packet_times), average, std_dev)
+ 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__':
+ usage = "usage: gdbremote [options]"
+ description='''The command disassembles a GDB remote packet log.'''
+ parser = optparse.OptionParser(description=description, prog='gdbremote',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', '--color', action='store_true', dest='color', help='add terminal colors', default=False)
+ parser.add_option('-c', '--sort-by-count', action='store_true', dest='sort_count', help='display verbose debug info', default=False)
+ parser.add_option('--crashlog', type='string', dest='crashlog', help='symbolicate using a darwin crash log file', default=False)
+ try:
+ (options, args) = parser.parse_args(sys.argv[1:])
+ except:
+ print 'error: argument error'
+ sys.exit(1)
+
+ options.colors = TerminalColors(options.color)
+ options.symbolicator = None
+ if options.crashlog:
+ import lldb
+ lldb.debugger = lldb.SBDebugger.Create()
+ import lldb.macosx.crashlog
+ options.symbolicator = lldb.macosx.crashlog.CrashLog(options.crashlog)
+ print '%s' % (options.symbolicator)
+
+ # This script is being run from the command line, create a debugger in case we are
+ # going to use any debugger functions in our function.
+ if len(args):
+ for file in args:
+ print '#----------------------------------------------------------------------'
+ print "# GDB remote log file: '%s'" % file
+ print '#----------------------------------------------------------------------'
+ parse_gdb_log_file (file, options)
+ if options.symbolicator:
+ print '%s' % (options.symbolicator)
+ else:
+ parse_gdb_log(sys.stdin, options)
+
+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/examples/python/globals.py b/examples/python/globals.py
new file mode 100755
index 0000000000000..fb2739c8b69c0
--- /dev/null
+++ b/examples/python/globals.py
@@ -0,0 +1,72 @@
+#!/usr/bin/python
+
+#----------------------------------------------------------------------
+# For the shells csh, tcsh:
+# ( setenv PYTHONPATH /Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Resources/Python ; ./globals.py <path> [<path> ...])
+#
+# For the shells sh, bash:
+# PYTHONPATH=/Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Resources/Python ./globals.py <path> [<path> ...]
+#----------------------------------------------------------------------
+
+import lldb
+import commands
+import optparse
+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)
+ 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
+ for symbol in module.symbols:
+ if symbol.type == lldb.eSymbolTypeData:
+ # 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)
+ 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
+ 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
+ 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".')
+ try:
+ (options, args) = parser.parse_args(command_args)
+ except:
+ return
+
+ for path in args:
+ get_globals (path, options)
+
+if __name__ == '__main__':
+ lldb.debugger = lldb.SBDebugger.Create()
+ globals (sys.argv[1:])
+
diff --git a/examples/python/jump.py b/examples/python/jump.py
new file mode 100644
index 0000000000000..c904009bb4052
--- /dev/null
+++ b/examples/python/jump.py
@@ -0,0 +1,173 @@
+import lldb, re
+
+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
+ filename:number - Line /number/ in file /filename/
+ function - The start of /function/
+ *address - The pointer target of /address/, which must be a literal (but see `` in LLDB)
+
+ We explicitly do not handle filename:function because it is ambiguous in Objective-C.
+
+ This function returns a list of addresses."""
+
+ breakpoint = None
+ target = frame.GetThread().GetProcess().GetTarget()
+
+ matched = False
+
+ if (not matched):
+ mo = re.match("^([0-9]+)$", linespec)
+ if (mo != None):
+ matched = True
+ #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.")
+ return
+ breakpoint = target.BreakpointCreateByLocation (line_entry.GetFileSpec(), line_number)
+
+ if (not matched):
+ mo = re.match("^\+([0-9]+)$", linespec)
+ if (mo != None):
+ matched = True
+ #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.")
+ return
+ breakpoint = target.BreakpointCreateByLocation(line_entry.GetFileSpec(), (line_entry.GetLine() + line_number))
+
+ if (not matched):
+ mo = re.match("^\-([0-9]+)$", linespec)
+ if (mo != None):
+ matched = True
+ #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.")
+ return
+ breakpoint = target.BreakpointCreateByLocation(line_entry.GetFileSpec(), (line_entry.GetLine() - line_number))
+
+ if (not matched):
+ mo = re.match("^(.*):([0-9]+)$", linespec)
+ if (mo != None):
+ matched = True
+ #print "Matched <filename>:<linenum>"
+ file_name = mo.group(1)
+ line_number = int(mo.group(2))
+ breakpoint = target.BreakpointCreateByLocation(file_name, line_number)
+
+ if (not matched):
+ mo = re.match("\*((0x)?([0-9a-f]+))$", linespec)
+ if (mo != None):
+ matched = True
+ #print "Matched <address-expression>"
+ address = long(mo.group(1), base=0)
+ breakpoint = target.BreakpointCreateByAddress(address)
+
+ if (not matched):
+ #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.")
+
+ addr_list = []
+
+ for location_index in range(num_locations):
+ location = breakpoint.GetLocationAtIndex(location_index)
+ addr_list.append(location.GetAddress())
+
+ target.BreakpointDelete(breakpoint.GetID())
+
+ return addr_list
+
+def usage_string():
+ return """ Sets the program counter to a specific address.
+
+Syntax: jump <linespec> [<location-id>]
+
+Command Options Usage:
+ jump <linenum>
+ jump +<count>
+ jump -<count>
+ jump <filename>:<linenum>
+ jump <function-name>
+ jump *<address-expression>
+
+<location-id> serves to disambiguate when multiple locations could be meant."""
+
+def jump (debugger, command, result, internal_dict):
+ if (command == ""):
+ result.AppendMessage(usage_string())
+
+ args = command.split()
+
+ if not debugger.IsValid():
+ result.AppendMessage("Invalid debugger!")
+ return
+
+ target = debugger.GetSelectedTarget()
+ if not target.IsValid():
+ result.AppendMessage("jump requires a valid target.")
+ return
+
+ process = target.GetProcess()
+ if not process.IsValid():
+ result.AppendMessage("jump requires a valid process.")
+ return
+
+ thread = process.GetSelectedThread()
+ if not thread.IsValid():
+ result.AppendMessage("jump requires a valid thread.")
+ return
+
+ frame = thread.GetSelectedFrame()
+ if not frame.IsValid():
+ result.AppendMessage("jump requires a valid frame.")
+ return
+
+ addresses = parse_linespec(args[0], frame, result)
+
+ stream = lldb.SBStream()
+
+ if len(addresses) == 0:
+ return
+
+ desired_address = addresses[0]
+
+ if len(addresses) > 1:
+ if len(args) == 2:
+ desired_index = int(args[1])
+ 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.")
+ return
+ else:
+ index = 0
+ 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())
+ index = index + 1
+ result.AppendMessage("Please type 'jump " + command + " <location-id>' to choose one.")
+ return
+
+ frame.SetPC(desired_address.GetLoadAddress(target))
+
+if lldb.debugger:
+ # Module is being run inside the LLDB interpreter
+ jump.__doc__ = usage_string()
+ lldb.debugger.HandleCommand('command script add -f jump.jump jump')
+ print 'The "jump" command has been installed, type "help jump" or "jump <ENTER>" for detailed help.'
diff --git a/examples/python/lldb_module_utils.py b/examples/python/lldb_module_utils.py
new file mode 100644
index 0000000000000..37f33ba416a50
--- /dev/null
+++ b/examples/python/lldb_module_utils.py
@@ -0,0 +1,59 @@
+#!/usr/bin/python
+
+import lldb
+import optparse
+import shlex
+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))
+ 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' \ No newline at end of file
diff --git a/examples/python/lldbtk.py b/examples/python/lldbtk.py
new file mode 100644
index 0000000000000..7ada9d77b30c7
--- /dev/null
+++ b/examples/python/lldbtk.py
@@ -0,0 +1,544 @@
+#!/usr/bin/python
+
+import lldb
+import shlex
+import sys
+from Tkinter import *
+import ttk
+
+class ValueTreeItemDelegate(object):
+ def __init__(self, value):
+ self.value = value
+
+ def get_item_dictionary(self):
+ name = self.value.name
+ if name is None:
+ name = ''
+ typename = self.value.type
+ if typename is None:
+ typename = ''
+ value = self.value.value
+ if value is None:
+ value = ''
+ summary = self.value.summary
+ 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 }
+
+ 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_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);
+ 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 }
+
+ def get_child_item_dictionaries(self):
+ item_dicts = list()
+ variables = self.frame.GetVariables(True, True, True, True)
+ n = variables.GetSize()
+ for i in range(n):
+ item_delegate = ValueTreeItemDelegate(variables[i])
+ 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,
+ 'summary': summary,
+ '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
+
+class ProcessTreeItemDelegate(object):
+ def __init__(self, process):
+ self.process = process
+
+ def get_item_dictionary(self):
+ id = self.process.GetProcessID()
+ 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 }
+
+ def get_child_item_dictionaries(self):
+ item_dicts = list()
+ for thread in self.process:
+ item_delegate = ThreadTreeItemDelegate(thread)
+ 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 }
+
+ def get_child_item_dictionaries(self):
+ item_dicts = list()
+ image_item_delegate = TargetImagesTreeItemDelegate(self.target)
+ item_dicts.append(image_item_delegate.get_item_dictionary())
+ return item_dicts
+
+class TargetImagesTreeItemDelegate(object):
+ def __init__(self, target):
+ self.target = target
+
+ def get_item_dictionary(self):
+ 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 }
+
+ 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)
+ 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
+ self.index = index
+
+ def get_item_dictionary(self):
+ 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 }
+
+ def get_child_item_dictionaries(self):
+ item_dicts = list()
+ 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)
+ item_dicts.append(symbols_item_delegate.get_item_dictionary())
+
+ 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
+
+ def get_item_dictionary(self):
+ name = 'sections'
+ value = ''
+ summary = '%u sections' % (self.module.GetNumSections())
+ return { '#0' : name,
+ 'value': value,
+ 'summary': summary,
+ 'children' : True,
+ 'tree-item-delegate' : self }
+
+ def get_child_item_dictionaries(self):
+ item_dicts = list()
+ num_sections = self.module.GetNumSections()
+ for i in range(num_sections):
+ section = self.module.GetSectionAtIndex(i)
+ image_item_delegate = SectionTreeItemDelegate(self.target, section)
+ 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
+
+ def get_item_dictionary(self):
+ name = self.section.name
+ section_load_addr = self.section.GetLoadAddress(self.target)
+ if section_load_addr != lldb.LLDB_INVALID_ADDRESS:
+ value = '0x%16.16x' % (section_load_addr)
+ 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 }
+
+ def get_child_item_dictionaries(self):
+ item_dicts = list()
+ num_sections = self.section.GetNumSubSections()
+ 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())
+ return item_dicts
+
+class ModuleCompileUnitsTreeItemDelegate(object):
+ def __init__(self, target, module):
+ self.target = target
+ self.module = module
+
+ def get_item_dictionary(self):
+ 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 }
+
+ def get_child_item_dictionaries(self):
+ item_dicts = list()
+ num_cus = self.module.GetNumCompileUnits()
+ for i in range(num_cus):
+ cu = self.module.GetCompileUnitAtIndex(i)
+ image_item_delegate = CompileUnitTreeItemDelegate(self.target, cu)
+ 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
+
+ def get_item_dictionary(self):
+ name = self.cu.GetFileSpec().basename
+ value = ''
+ num_lines = self.cu.GetNumLineEntries()
+ summary = ''
+ return { '#0' : name,
+ 'value': value,
+ 'summary': summary,
+ 'children' : num_lines > 0,
+ 'tree-item-delegate' : self }
+
+ def get_child_item_dictionaries(self):
+ item_dicts = list()
+ item_delegate = LineTableTreeItemDelegate(self.target, self.cu)
+ 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
+
+ def get_item_dictionary(self):
+ name = 'line table'
+ 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 }
+
+ 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_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
+ self.index = index
+
+ def get_item_dictionary(self):
+ name = str(self.index)
+ address = self.line_entry.GetStartAddress()
+ load_addr = address.GetLoadAddress(self.target)
+ if load_addr != lldb.LLDB_INVALID_ADDRESS:
+ 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 }
+
+ 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
+
+ def get_item_dictionary(self):
+ address = self.instr.GetAddress()
+ load_addr = address.GetLoadAddress(self.target)
+ if load_addr != lldb.LLDB_INVALID_ADDRESS:
+ 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)
+ summary = self.instr.GetComment(self.target)
+ 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
+
+ def get_item_dictionary(self):
+ name = 'symbols'
+ value = ''
+ summary = '%u symbols' % (self.module.GetNumSymbols())
+ 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)
+ 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
+ self.index = index
+
+ def get_item_dictionary(self):
+ address = self.symbol.GetStartAddress()
+ name = '[%u]' % self.index
+ symbol_load_addr = address.GetLoadAddress(self.target)
+ if symbol_load_addr != lldb.LLDB_INVALID_ADDRESS:
+ value = '0x%16.16x' % (symbol_load_addr)
+ 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 }
+
+ 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)
+ self.master.title(title)
+ self.delegate = delegate
+ self.columns_dicts = column_dicts
+ self.item_id_to_item_dict = dict()
+ frame = Frame(self)
+ 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)):
+ 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)
+ 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'])
+
+ # 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)
+
+ def insert_items(self, parent_id, item_dicts):
+ for item_dict in item_dicts:
+ name = None
+ values = list()
+ first = True
+ for columns_dict in self.columns_dicts:
+ if first:
+ name = item_dict[columns_dict['id']]
+ 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)
+ 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)
+ if len(children):
+ first_child = children[0]
+ # if the node only has a 'dummy' child, remove it and
+ # build new directory; skip if the node is already
+ # populated
+ 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()
+ 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...
+ target = debugger.GetSelectedTarget()
+ if not target:
+ print >>result, "invalid target"
+ return
+ process = target.GetProcess()
+ if not process:
+ print >>result, "invalid process"
+ return
+ thread = process.GetSelectedThread()
+ if not thread:
+ print >>result, "invalid thread"
+ return
+ frame = thread.GetSelectedFrame()
+ if not frame:
+ print >>result, "invalid frame"
+ 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')
+ 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...
+ target = debugger.GetSelectedTarget()
+ if not target:
+ print >>result, "invalid target"
+ return
+ process = target.GetProcess()
+ if not process:
+ 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 }];
+ command_args = shlex.split(command)
+ 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...
+ 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 }];
+ command_args = shlex.split(command)
+ tree = DelegateTree(columnd_dicts, TargetTreeItemDelegate(target), 'Target', 'lldb-tk-target')
+ tree.mainloop()
+
diff --git a/examples/python/mach_o.py b/examples/python/mach_o.py
new file mode 100755
index 0000000000000..a609b09ed0ebf
--- /dev/null
+++ b/examples/python/mach_o.py
@@ -0,0 +1,1687 @@
+#!/usr/bin/python
+
+import cmd
+import dict_utils
+import file_extract
+import optparse
+import re
+import struct
+import string
+import StringIO
+import sys
+import uuid
+
+# Mach header "magic" constants
+MH_MAGIC = 0xfeedface
+MH_CIGAM = 0xcefaedfe
+MH_MAGIC_64 = 0xfeedfacf
+MH_CIGAM_64 = 0xcffaedfe
+FAT_MAGIC = 0xcafebabe
+FAT_CIGAM = 0xbebafeca
+
+# Mach haeder "filetype" constants
+MH_OBJECT = 0x00000001
+MH_EXECUTE = 0x00000002
+MH_FVMLIB = 0x00000003
+MH_CORE = 0x00000004
+MH_PRELOAD = 0x00000005
+MH_DYLIB = 0x00000006
+MH_DYLINKER = 0x00000007
+MH_BUNDLE = 0x00000008
+MH_DYLIB_STUB = 0x00000009
+MH_DSYM = 0x0000000a
+MH_KEXT_BUNDLE = 0x0000000b
+
+# Mach haeder "flag" constant bits
+MH_NOUNDEFS = 0x00000001
+MH_INCRLINK = 0x00000002
+MH_DYLDLINK = 0x00000004
+MH_BINDATLOAD = 0x00000008
+MH_PREBOUND = 0x00000010
+MH_SPLIT_SEGS = 0x00000020
+MH_LAZY_INIT = 0x00000040
+MH_TWOLEVEL = 0x00000080
+MH_FORCE_FLAT = 0x00000100
+MH_NOMULTIDEFS = 0x00000200
+MH_NOFIXPREBINDING = 0x00000400
+MH_PREBINDABLE = 0x00000800
+MH_ALLMODSBOUND = 0x00001000
+MH_SUBSECTIONS_VIA_SYMBOLS = 0x00002000
+MH_CANONICAL = 0x00004000
+MH_WEAK_DEFINES = 0x00008000
+MH_BINDS_TO_WEAK = 0x00010000
+MH_ALLOW_STACK_EXECUTION = 0x00020000
+MH_ROOT_SAFE = 0x00040000
+MH_SETUID_SAFE = 0x00080000
+MH_NO_REEXPORTED_DYLIBS = 0x00100000
+MH_PIE = 0x00200000
+MH_DEAD_STRIPPABLE_DYLIB = 0x00400000
+MH_HAS_TLV_DESCRIPTORS = 0x00800000
+MH_NO_HEAP_EXECUTION = 0x01000000
+
+# Mach load command constants
+LC_REQ_DYLD = 0x80000000
+LC_SEGMENT = 0x00000001
+LC_SYMTAB = 0x00000002
+LC_SYMSEG = 0x00000003
+LC_THREAD = 0x00000004
+LC_UNIXTHREAD = 0x00000005
+LC_LOADFVMLIB = 0x00000006
+LC_IDFVMLIB = 0x00000007
+LC_IDENT = 0x00000008
+LC_FVMFILE = 0x00000009
+LC_PREPAGE = 0x0000000a
+LC_DYSYMTAB = 0x0000000b
+LC_LOAD_DYLIB = 0x0000000c
+LC_ID_DYLIB = 0x0000000d
+LC_LOAD_DYLINKER = 0x0000000e
+LC_ID_DYLINKER = 0x0000000f
+LC_PREBOUND_DYLIB = 0x00000010
+LC_ROUTINES = 0x00000011
+LC_SUB_FRAMEWORK = 0x00000012
+LC_SUB_UMBRELLA = 0x00000013
+LC_SUB_CLIENT = 0x00000014
+LC_SUB_LIBRARY = 0x00000015
+LC_TWOLEVEL_HINTS = 0x00000016
+LC_PREBIND_CKSUM = 0x00000017
+LC_LOAD_WEAK_DYLIB = 0x00000018 | LC_REQ_DYLD
+LC_SEGMENT_64 = 0x00000019
+LC_ROUTINES_64 = 0x0000001a
+LC_UUID = 0x0000001b
+LC_RPATH = 0x0000001c | LC_REQ_DYLD
+LC_CODE_SIGNATURE = 0x0000001d
+LC_SEGMENT_SPLIT_INFO = 0x0000001e
+LC_REEXPORT_DYLIB = 0x0000001f | LC_REQ_DYLD
+LC_LAZY_LOAD_DYLIB = 0x00000020
+LC_ENCRYPTION_INFO = 0x00000021
+LC_DYLD_INFO = 0x00000022
+LC_DYLD_INFO_ONLY = 0x00000022 | LC_REQ_DYLD
+LC_LOAD_UPWARD_DYLIB = 0x00000023 | LC_REQ_DYLD
+LC_VERSION_MIN_MACOSX = 0x00000024
+LC_VERSION_MIN_IPHONEOS = 0x00000025
+LC_FUNCTION_STARTS = 0x00000026
+LC_DYLD_ENVIRONMENT = 0x00000027
+
+# Mach CPU constants
+CPU_ARCH_MASK = 0xff000000
+CPU_ARCH_ABI64 = 0x01000000
+CPU_TYPE_ANY = 0xffffffff
+CPU_TYPE_VAX = 1
+CPU_TYPE_MC680x0 = 6
+CPU_TYPE_I386 = 7
+CPU_TYPE_X86_64 = CPU_TYPE_I386 | CPU_ARCH_ABI64
+CPU_TYPE_MIPS = 8
+CPU_TYPE_MC98000 = 10
+CPU_TYPE_HPPA = 11
+CPU_TYPE_ARM = 12
+CPU_TYPE_MC88000 = 13
+CPU_TYPE_SPARC = 14
+CPU_TYPE_I860 = 15
+CPU_TYPE_ALPHA = 16
+CPU_TYPE_POWERPC = 18
+CPU_TYPE_POWERPC64 = CPU_TYPE_POWERPC | CPU_ARCH_ABI64
+
+# VM protection constants
+VM_PROT_READ = 1
+VM_PROT_WRITE = 2
+VM_PROT_EXECUTE = 4
+
+# VM protection constants
+N_STAB = 0xe0
+N_PEXT = 0x10
+N_TYPE = 0x0e
+N_EXT = 0x01
+
+# Values for nlist N_TYPE bits of the "Mach.NList.type" field.
+N_UNDF = 0x0
+N_ABS = 0x2
+N_SECT = 0xe
+N_PBUD = 0xc
+N_INDR = 0xa
+
+# Section indexes for the "Mach.NList.sect_idx" fields
+NO_SECT = 0
+MAX_SECT = 255
+
+# Stab defines
+N_GSYM = 0x20
+N_FNAME = 0x22
+N_FUN = 0x24
+N_STSYM = 0x26
+N_LCSYM = 0x28
+N_BNSYM = 0x2e
+N_OPT = 0x3c
+N_RSYM = 0x40
+N_SLINE = 0x44
+N_ENSYM = 0x4e
+N_SSYM = 0x60
+N_SO = 0x64
+N_OSO = 0x66
+N_LSYM = 0x80
+N_BINCL = 0x82
+N_SOL = 0x84
+N_PARAMS = 0x86
+N_VERSION = 0x88
+N_OLEVEL = 0x8A
+N_PSYM = 0xa0
+N_EINCL = 0xa2
+N_ENTRY = 0xa4
+N_LBRAC = 0xc0
+N_EXCL = 0xc2
+N_RBRAC = 0xe0
+N_BCOMM = 0xe2
+N_ECOMM = 0xe4
+N_ECOML = 0xe8
+N_LENG = 0xfe
+
+vm_prot_names = [ '---', 'r--', '-w-', 'rw-', '--x', 'r-x', '-wx', 'rwx' ]
+
+def dump_memory(base_addr, data, hex_bytes_len, num_per_line):
+ hex_bytes = data.encode('hex')
+ if hex_bytes_len == -1:
+ hex_bytes_len = len(hex_bytes)
+ addr = base_addr
+ ascii_str = ''
+ i = 0
+ while i < hex_bytes_len:
+ if ((i/2) % num_per_line) == 0:
+ if i > 0:
+ print ' %s' % (ascii_str)
+ ascii_str = ''
+ print '0x%8.8x:' % (addr+i),
+ hex_byte = hex_bytes[i:i+2]
+ print hex_byte,
+ int_byte = int (hex_byte, 16)
+ ascii_char = '%c' % (int_byte)
+ if int_byte >= 32 and int_byte < 127:
+ ascii_str += ascii_char
+ else:
+ ascii_str += '.'
+ i = i + 2
+ if ascii_str:
+ if (i/2) % num_per_line:
+ padding = num_per_line - ((i/2) % num_per_line)
+ else:
+ padding = 0
+ print '%*s%s' % (padding*3+1,'',ascii_str)
+ print
+
+
+class TerminalColors:
+ '''Simple terminal colors class'''
+ def __init__(self, enabled = True):
+ # TODO: discover terminal type from "file" and disable if
+ # it can't handle the color codes
+ self.enabled = enabled
+
+ def reset(self):
+ '''Reset all terminal colors and formatting.'''
+ if self.enabled:
+ return "\x1b[0m";
+ return ''
+
+ def bold(self, on = True):
+ '''Enable or disable bold depending on the "on" parameter.'''
+ if self.enabled:
+ if on:
+ return "\x1b[1m";
+ else:
+ return "\x1b[22m";
+ return ''
+
+ def italics(self, on = True):
+ '''Enable or disable italics depending on the "on" parameter.'''
+ if self.enabled:
+ if on:
+ return "\x1b[3m";
+ else:
+ return "\x1b[23m";
+ return ''
+
+ def underline(self, on = True):
+ '''Enable or disable underline depending on the "on" parameter.'''
+ if self.enabled:
+ if on:
+ return "\x1b[4m";
+ else:
+ return "\x1b[24m";
+ return ''
+
+ def inverse(self, on = True):
+ '''Enable or disable inverse depending on the "on" parameter.'''
+ if self.enabled:
+ if on:
+ return "\x1b[7m";
+ else:
+ return "\x1b[27m";
+ return ''
+
+ def strike(self, on = True):
+ '''Enable or disable strike through depending on the "on" parameter.'''
+ if self.enabled:
+ if on:
+ return "\x1b[9m";
+ else:
+ return "\x1b[29m";
+ return ''
+
+ def black(self, fg = True):
+ '''Set the foreground or background color to black.
+ The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
+ if self.enabled:
+ if fg:
+ return "\x1b[30m";
+ else:
+ return "\x1b[40m";
+ return ''
+
+ def red(self, fg = True):
+ '''Set the foreground or background color to red.
+ The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
+ if self.enabled:
+ if fg:
+ return "\x1b[31m";
+ else:
+ return "\x1b[41m";
+ return ''
+
+ def green(self, fg = True):
+ '''Set the foreground or background color to green.
+ The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
+ if self.enabled:
+ if fg:
+ return "\x1b[32m";
+ else:
+ return "\x1b[42m";
+ return ''
+
+ def yellow(self, fg = True):
+ '''Set the foreground or background color to yellow.
+ The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
+ if self.enabled:
+ if fg:
+ return "\x1b[43m";
+ else:
+ return "\x1b[33m";
+ return ''
+
+ def blue(self, fg = True):
+ '''Set the foreground or background color to blue.
+ The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
+ if self.enabled:
+ if fg:
+ return "\x1b[34m";
+ else:
+ return "\x1b[44m";
+ return ''
+
+ def magenta(self, fg = True):
+ '''Set the foreground or background color to magenta.
+ The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
+ if self.enabled:
+ if fg:
+ return "\x1b[35m";
+ else:
+ return "\x1b[45m";
+ return ''
+
+ def cyan(self, fg = True):
+ '''Set the foreground or background color to cyan.
+ The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
+ if self.enabled:
+ if fg:
+ return "\x1b[36m";
+ else:
+ return "\x1b[46m";
+ return ''
+
+ def white(self, fg = True):
+ '''Set the foreground or background color to white.
+ The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
+ if self.enabled:
+ if fg:
+ return "\x1b[37m";
+ else:
+ return "\x1b[47m";
+ return ''
+
+ def default(self, fg = True):
+ '''Set the foreground or background color to the default.
+ The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
+ if self.enabled:
+ if fg:
+ return "\x1b[39m";
+ else:
+ return "\x1b[49m";
+ return ''
+
+def swap_unpack_char():
+ """Returns the unpack prefix that will for non-native endian-ness."""
+ if struct.pack('H', 1).startswith("\x00"):
+ return '<'
+ return '>'
+
+
+def dump_hex_bytes(addr, s, bytes_per_line=16):
+ i = 0
+ line = ''
+ for ch in s:
+ if (i % bytes_per_line) == 0:
+ if line:
+ print line
+ line = '%#8.8x: ' % (addr + i)
+ line += "%02X " % ord(ch)
+ i += 1
+ print line
+
+def dump_hex_byte_string_diff(addr, a, b, bytes_per_line=16):
+ i = 0
+ line = ''
+ a_len = len(a)
+ b_len = len(b)
+ if a_len < b_len:
+ max_len = b_len
+ else:
+ max_len = a_len
+ tty_colors = TerminalColors (True)
+ for i in range(max_len):
+ ch = None
+ if i < a_len:
+ ch_a = a[i]
+ ch = ch_a
+ else:
+ ch_a = None
+ if i < b_len:
+ ch_b = b[i]
+ if not ch:
+ ch = ch_b
+ else:
+ ch_b = None
+ mismatch = ch_a != ch_b
+ if (i % bytes_per_line) == 0:
+ if line:
+ print line
+ line = '%#8.8x: ' % (addr + i)
+ if mismatch: line += tty_colors.red()
+ line += "%02X " % ord(ch)
+ if mismatch: line += tty_colors.default()
+ i += 1
+
+ print line
+
+class Mach:
+ """Class that does everything mach-o related"""
+
+ class Arch:
+ """Class that implements mach-o architectures"""
+
+ def __init__(self, c=0, s=0):
+ self.cpu=c
+ self.sub=s
+
+ def set_cpu_type(self, c):
+ self.cpu=c
+ def set_cpu_subtype(self, s):
+ self.sub=s
+ def set_arch(self, c, s):
+ self.cpu=c
+ self.sub=s
+ def is_64_bit(self):
+ return (self.cpu & CPU_ARCH_ABI64) != 0
+
+ cpu_infos = [
+ [ "arm" , CPU_TYPE_ARM , CPU_TYPE_ANY ],
+ [ "arm" , CPU_TYPE_ARM , 0 ],
+ [ "armv4" , CPU_TYPE_ARM , 5 ],
+ [ "armv6" , CPU_TYPE_ARM , 6 ],
+ [ "armv5" , CPU_TYPE_ARM , 7 ],
+ [ "xscale" , CPU_TYPE_ARM , 8 ],
+ [ "armv7" , CPU_TYPE_ARM , 9 ],
+ [ "armv7f" , CPU_TYPE_ARM , 10 ],
+ [ "armv7s" , CPU_TYPE_ARM , 11 ],
+ [ "armv7k" , CPU_TYPE_ARM , 12 ],
+ [ "armv7m" , CPU_TYPE_ARM , 15 ],
+ [ "armv7em" , CPU_TYPE_ARM , 16 ],
+ [ "ppc" , CPU_TYPE_POWERPC , CPU_TYPE_ANY ],
+ [ "ppc" , CPU_TYPE_POWERPC , 0 ],
+ [ "ppc601" , CPU_TYPE_POWERPC , 1 ],
+ [ "ppc602" , CPU_TYPE_POWERPC , 2 ],
+ [ "ppc603" , CPU_TYPE_POWERPC , 3 ],
+ [ "ppc603e" , CPU_TYPE_POWERPC , 4 ],
+ [ "ppc603ev" , CPU_TYPE_POWERPC , 5 ],
+ [ "ppc604" , CPU_TYPE_POWERPC , 6 ],
+ [ "ppc604e" , CPU_TYPE_POWERPC , 7 ],
+ [ "ppc620" , CPU_TYPE_POWERPC , 8 ],
+ [ "ppc750" , CPU_TYPE_POWERPC , 9 ],
+ [ "ppc7400" , CPU_TYPE_POWERPC , 10 ],
+ [ "ppc7450" , CPU_TYPE_POWERPC , 11 ],
+ [ "ppc970" , CPU_TYPE_POWERPC , 100 ],
+ [ "ppc64" , CPU_TYPE_POWERPC64 , 0 ],
+ [ "ppc970-64" , CPU_TYPE_POWERPC64 , 100 ],
+ [ "i386" , CPU_TYPE_I386 , 3 ],
+ [ "i486" , CPU_TYPE_I386 , 4 ],
+ [ "i486sx" , CPU_TYPE_I386 , 0x84 ],
+ [ "i386" , CPU_TYPE_I386 , CPU_TYPE_ANY ],
+ [ "x86_64" , CPU_TYPE_X86_64 , 3 ],
+ [ "x86_64" , CPU_TYPE_X86_64 , CPU_TYPE_ANY ],
+ ]
+
+ def __str__(self):
+ for info in self.cpu_infos:
+ if self.cpu == info[1] and (self.sub & 0x00ffffff) == info[2]:
+ return info[0]
+ return "{0}.{1}".format(self.cpu,self.sub)
+
+
+ class Magic(dict_utils.Enum):
+
+ enum = {
+ 'MH_MAGIC' : MH_MAGIC,
+ 'MH_CIGAM' : MH_CIGAM,
+ 'MH_MAGIC_64' : MH_MAGIC_64,
+ 'MH_CIGAM_64' : MH_CIGAM_64,
+ 'FAT_MAGIC' : FAT_MAGIC,
+ 'FAT_CIGAM' : FAT_CIGAM
+ }
+
+ def __init__(self, initial_value = 0):
+ dict_utils.Enum.__init__(self, initial_value, self.enum)
+
+ def is_skinny_mach_file(self):
+ return self.value == MH_MAGIC or self.value == MH_CIGAM or self.value == MH_MAGIC_64 or self.value == MH_CIGAM_64
+
+ def is_universal_mach_file(self):
+ return self.value == FAT_MAGIC or self.value == FAT_CIGAM
+
+ def unpack(self, data):
+ data.set_byte_order('native')
+ self.value = data.get_uint32();
+
+ def get_byte_order(self):
+ if self.value == MH_CIGAM or self.value == MH_CIGAM_64 or self.value == FAT_CIGAM:
+ return swap_unpack_char()
+ else:
+ return '='
+
+ def is_64_bit(self):
+ return self.value == MH_MAGIC_64 or self.value == MH_CIGAM_64
+
+ def __init__(self):
+ self.magic = Mach.Magic()
+ self.content = None
+ self.path = None
+
+ def extract (self, path, extractor):
+ self.path = path;
+ self.unpack(extractor)
+
+ def parse(self, path):
+ self.path = path;
+ try:
+ f = open(self.path)
+ file_extractor = file_extract.FileExtract(f, '=')
+ self.unpack(file_extractor)
+ #f.close()
+ except IOError as (errno, strerror):
+ print "I/O error({0}): {1}".format(errno, strerror)
+ except ValueError:
+ print "Could not convert data to an integer."
+ except:
+ print "Unexpected error:", sys.exc_info()[0]
+ raise
+
+ def compare(self, rhs):
+ self.content.compare(rhs.content)
+
+ def dump(self, options = None):
+ self.content.dump(options)
+
+ def dump_header(self, dump_description = True, options = None):
+ self.content.dump_header(dump_description, options)
+
+ def dump_load_commands(self, dump_description = True, options = None):
+ self.content.dump_load_commands(dump_description, options)
+
+ def dump_sections(self, dump_description = True, options = None):
+ self.content.dump_sections(dump_description, options)
+
+ def dump_section_contents(self, options):
+ self.content.dump_section_contents(options)
+
+ def dump_symtab(self, dump_description = True, options = None):
+ self.content.dump_symtab(dump_description, options)
+
+ def dump_symbol_names_matching_regex(self, regex, file=None):
+ self.content.dump_symbol_names_matching_regex(regex, file)
+
+ def description(self):
+ return self.content.description()
+
+ def unpack(self, data):
+ self.magic.unpack(data)
+ if self.magic.is_skinny_mach_file():
+ self.content = Mach.Skinny(self.path)
+ elif self.magic.is_universal_mach_file():
+ self.content = Mach.Universal(self.path)
+ else:
+ self.content = None
+
+ if self.content != None:
+ self.content.unpack(data, self.magic)
+
+ def is_valid(self):
+ return self.content != None
+
+ class Universal:
+
+ def __init__(self, path):
+ self.path = path
+ self.type = 'universal'
+ self.file_off = 0
+ self.magic = None
+ self.nfat_arch = 0
+ self.archs = list()
+
+ def description(self):
+ s = '%#8.8x: %s (' % (self.file_off, self.path)
+ archs_string = ''
+ for arch in self.archs:
+ if len(archs_string):
+ archs_string += ', '
+ archs_string += '%s' % arch.arch
+ s += archs_string
+ s += ')'
+ return s
+
+ def unpack(self, data, magic = None):
+ self.file_off = data.tell()
+ if magic is None:
+ self.magic = Mach.Magic()
+ self.magic.unpack(data)
+ else:
+ self.magic = magic
+ self.file_off = self.file_off - 4
+ # Universal headers are always in big endian
+ data.set_byte_order('big')
+ self.nfat_arch = data.get_uint32()
+ for i in range(self.nfat_arch):
+ self.archs.append(Mach.Universal.ArchInfo())
+ self.archs[i].unpack(data)
+ for i in range(self.nfat_arch):
+ self.archs[i].mach = Mach.Skinny(self.path)
+ data.seek (self.archs[i].offset, 0)
+ skinny_magic = Mach.Magic()
+ skinny_magic.unpack (data)
+ self.archs[i].mach.unpack(data, skinny_magic)
+
+ def compare(self, rhs):
+ print 'error: comparing two universal files is not supported yet'
+ return False
+
+ def dump(self, options):
+ if options.dump_header:
+ print
+ print "Universal Mach File: magic = %s, nfat_arch = %u" % (self.magic, self.nfat_arch)
+ print
+ if self.nfat_arch > 0:
+ if options.dump_header:
+ self.archs[0].dump_header(True, options)
+ for i in range(self.nfat_arch):
+ self.archs[i].dump_flat(options)
+ if options.dump_header:
+ print
+ for i in range(self.nfat_arch):
+ self.archs[i].mach.dump(options)
+
+ def dump_header(self, dump_description = True, options = None):
+ if dump_description:
+ print self.description()
+ for i in range(self.nfat_arch):
+ self.archs[i].mach.dump_header(True, options)
+ print
+
+ def dump_load_commands(self, dump_description = True, options = None):
+ if dump_description:
+ print self.description()
+ for i in range(self.nfat_arch):
+ self.archs[i].mach.dump_load_commands(True, options)
+ print
+
+ def dump_sections(self, dump_description = True, options = None):
+ if dump_description:
+ print self.description()
+ for i in range(self.nfat_arch):
+ self.archs[i].mach.dump_sections(True, options)
+ print
+
+ def dump_section_contents(self, options):
+ for i in range(self.nfat_arch):
+ self.archs[i].mach.dump_section_contents(options)
+ print
+
+ def dump_symtab(self, dump_description = True, options = None):
+ if dump_description:
+ print self.description()
+ for i in range(self.nfat_arch):
+ self.archs[i].mach.dump_symtab(True, options)
+ print
+
+ def dump_symbol_names_matching_regex(self, regex, file=None):
+ for i in range(self.nfat_arch):
+ self.archs[i].mach.dump_symbol_names_matching_regex(regex, file)
+
+ class ArchInfo:
+
+ def __init__(self):
+ self.arch = Mach.Arch(0,0)
+ self.offset = 0
+ self.size = 0
+ self.align = 0
+ self.mach = None
+
+ def unpack(self, data):
+ # Universal headers are always in big endian
+ data.set_byte_order('big')
+ self.arch.cpu, self.arch.sub, self.offset, self.size, self.align = data.get_n_uint32(5)
+
+ def dump_header(self, dump_description = True, options = None):
+ if options.verbose:
+ print "CPU SUBTYPE OFFSET SIZE ALIGN"
+ print "---------- ---------- ---------- ---------- ----------"
+ else:
+ print "ARCH FILEOFFSET FILESIZE ALIGN"
+ print "---------- ---------- ---------- ----------"
+ def dump_flat(self, options):
+ if options.verbose:
+ print "%#8.8x %#8.8x %#8.8x %#8.8x %#8.8x" % (self.arch.cpu, self.arch.sub, self.offset, self.size, self.align)
+ else:
+ print "%-10s %#8.8x %#8.8x %#8.8x" % (self.arch, self.offset, self.size, self.align)
+ def dump(self):
+ print " cputype: %#8.8x" % self.arch.cpu
+ print "cpusubtype: %#8.8x" % self.arch.sub
+ print " offset: %#8.8x" % self.offset
+ print " size: %#8.8x" % self.size
+ print " align: %#8.8x" % self.align
+ def __str__(self):
+ return "Mach.Universal.ArchInfo: %#8.8x %#8.8x %#8.8x %#8.8x %#8.8x" % (self.arch.cpu, self.arch.sub, self.offset, self.size, self.align)
+ def __repr__(self):
+ return "Mach.Universal.ArchInfo: %#8.8x %#8.8x %#8.8x %#8.8x %#8.8x" % (self.arch.cpu, self.arch.sub, self.offset, self.size, self.align)
+
+ class Flags:
+
+ def __init__(self, b):
+ self.bits = b
+
+ def __str__(self):
+ s = ''
+ if self.bits & MH_NOUNDEFS:
+ s += 'MH_NOUNDEFS | '
+ if self.bits & MH_INCRLINK:
+ s += 'MH_INCRLINK | '
+ if self.bits & MH_DYLDLINK:
+ s += 'MH_DYLDLINK | '
+ if self.bits & MH_BINDATLOAD:
+ s += 'MH_BINDATLOAD | '
+ if self.bits & MH_PREBOUND:
+ s += 'MH_PREBOUND | '
+ if self.bits & MH_SPLIT_SEGS:
+ s += 'MH_SPLIT_SEGS | '
+ if self.bits & MH_LAZY_INIT:
+ s += 'MH_LAZY_INIT | '
+ if self.bits & MH_TWOLEVEL:
+ s += 'MH_TWOLEVEL | '
+ if self.bits & MH_FORCE_FLAT:
+ s += 'MH_FORCE_FLAT | '
+ if self.bits & MH_NOMULTIDEFS:
+ s += 'MH_NOMULTIDEFS | '
+ if self.bits & MH_NOFIXPREBINDING:
+ s += 'MH_NOFIXPREBINDING | '
+ if self.bits & MH_PREBINDABLE:
+ s += 'MH_PREBINDABLE | '
+ if self.bits & MH_ALLMODSBOUND:
+ s += 'MH_ALLMODSBOUND | '
+ if self.bits & MH_SUBSECTIONS_VIA_SYMBOLS:
+ s += 'MH_SUBSECTIONS_VIA_SYMBOLS | '
+ if self.bits & MH_CANONICAL:
+ s += 'MH_CANONICAL | '
+ if self.bits & MH_WEAK_DEFINES:
+ s += 'MH_WEAK_DEFINES | '
+ if self.bits & MH_BINDS_TO_WEAK:
+ s += 'MH_BINDS_TO_WEAK | '
+ if self.bits & MH_ALLOW_STACK_EXECUTION:
+ s += 'MH_ALLOW_STACK_EXECUTION | '
+ if self.bits & MH_ROOT_SAFE:
+ s += 'MH_ROOT_SAFE | '
+ if self.bits & MH_SETUID_SAFE:
+ s += 'MH_SETUID_SAFE | '
+ if self.bits & MH_NO_REEXPORTED_DYLIBS:
+ s += 'MH_NO_REEXPORTED_DYLIBS | '
+ if self.bits & MH_PIE:
+ s += 'MH_PIE | '
+ if self.bits & MH_DEAD_STRIPPABLE_DYLIB:
+ s += 'MH_DEAD_STRIPPABLE_DYLIB | '
+ if self.bits & MH_HAS_TLV_DESCRIPTORS:
+ s += 'MH_HAS_TLV_DESCRIPTORS | '
+ if self.bits & MH_NO_HEAP_EXECUTION:
+ s += 'MH_NO_HEAP_EXECUTION | '
+ # Strip the trailing " |" if we have any flags
+ if len(s) > 0:
+ s = s[0:-2]
+ return s
+
+ class FileType(dict_utils.Enum):
+
+ enum = {
+ 'MH_OBJECT' : MH_OBJECT ,
+ 'MH_EXECUTE' : MH_EXECUTE ,
+ 'MH_FVMLIB' : MH_FVMLIB ,
+ 'MH_CORE' : MH_CORE ,
+ 'MH_PRELOAD' : MH_PRELOAD ,
+ 'MH_DYLIB' : MH_DYLIB ,
+ 'MH_DYLINKER' : MH_DYLINKER ,
+ 'MH_BUNDLE' : MH_BUNDLE ,
+ 'MH_DYLIB_STUB' : MH_DYLIB_STUB ,
+ 'MH_DSYM' : MH_DSYM ,
+ 'MH_KEXT_BUNDLE' : MH_KEXT_BUNDLE
+ }
+
+ def __init__(self, initial_value = 0):
+ dict_utils.Enum.__init__(self, initial_value, self.enum)
+
+ class Skinny:
+
+ def __init__(self, path):
+ self.path = path
+ self.type = 'skinny'
+ self.data = None
+ self.file_off = 0
+ self.magic = 0
+ self.arch = Mach.Arch(0,0)
+ self.filetype = Mach.FileType(0)
+ self.ncmds = 0
+ self.sizeofcmds = 0
+ self.flags = Mach.Flags(0)
+ self.uuid = None
+ self.commands = list()
+ self.segments = list()
+ self.sections = list()
+ self.symbols = list()
+ self.sections.append(Mach.Section())
+
+ def description(self):
+ return '%#8.8x: %s (%s)' % (self.file_off, self.path, self.arch)
+
+ def unpack(self, data, magic = None):
+ self.data = data
+ self.file_off = data.tell()
+ if magic is None:
+ self.magic = Mach.Magic()
+ self.magic.unpack(data)
+ else:
+ self.magic = magic
+ self.file_off = self.file_off - 4
+ data.set_byte_order(self.magic.get_byte_order())
+ self.arch.cpu, self.arch.sub, self.filetype.value, self.ncmds, self.sizeofcmds, bits = data.get_n_uint32(6)
+ self.flags.bits = bits
+
+ if self.is_64_bit():
+ data.get_uint32() # Skip reserved word in mach_header_64
+
+ for i in range(0,self.ncmds):
+ lc = self.unpack_load_command (data)
+ self.commands.append (lc)
+
+ def get_data(self):
+ if self.data:
+ self.data.set_byte_order(self.magic.get_byte_order())
+ return self.data
+ return None
+
+ def unpack_load_command (self, data):
+ lc = Mach.LoadCommand()
+ lc.unpack (self, data)
+ lc_command = lc.command.get_enum_value();
+ if (lc_command == LC_SEGMENT or
+ lc_command == LC_SEGMENT_64):
+ lc = Mach.SegmentLoadCommand(lc)
+ lc.unpack(self, data)
+ elif (lc_command == LC_LOAD_DYLIB or
+ lc_command == LC_ID_DYLIB or
+ lc_command == LC_LOAD_WEAK_DYLIB or
+ lc_command == LC_REEXPORT_DYLIB):
+ lc = Mach.DylibLoadCommand(lc)
+ lc.unpack(self, data)
+ elif (lc_command == LC_LOAD_DYLINKER or
+ lc_command == LC_SUB_FRAMEWORK or
+ lc_command == LC_SUB_CLIENT or
+ lc_command == LC_SUB_UMBRELLA or
+ lc_command == LC_SUB_LIBRARY or
+ lc_command == LC_ID_DYLINKER or
+ lc_command == LC_RPATH):
+ lc = Mach.LoadDYLDLoadCommand(lc)
+ lc.unpack(self, data)
+ elif (lc_command == LC_DYLD_INFO_ONLY):
+ lc = Mach.DYLDInfoOnlyLoadCommand(lc)
+ lc.unpack(self, data)
+ elif (lc_command == LC_SYMTAB):
+ lc = Mach.SymtabLoadCommand(lc)
+ lc.unpack(self, data)
+ elif (lc_command == LC_DYSYMTAB):
+ lc = Mach.DYLDSymtabLoadCommand(lc)
+ lc.unpack(self, data)
+ elif (lc_command == LC_UUID):
+ lc = Mach.UUIDLoadCommand(lc)
+ lc.unpack(self, data)
+ elif (lc_command == LC_CODE_SIGNATURE or
+ lc_command == LC_SEGMENT_SPLIT_INFO or
+ lc_command == LC_FUNCTION_STARTS):
+ lc = Mach.DataBlobLoadCommand(lc)
+ lc.unpack(self, data)
+ elif (lc_command == LC_UNIXTHREAD):
+ lc = Mach.UnixThreadLoadCommand(lc)
+ lc.unpack(self, data)
+ elif (lc_command == LC_ENCRYPTION_INFO):
+ lc = Mach.EncryptionInfoLoadCommand(lc)
+ lc.unpack(self, data)
+ lc.skip(data)
+ return lc
+
+ def compare(self, rhs):
+ print "\nComparing:"
+ print "a) %s %s" % (self.arch, self.path)
+ print "b) %s %s" % (rhs.arch, rhs.path)
+ result = True
+ if self.type == rhs.type:
+ for lhs_section in self.sections[1:]:
+ rhs_section = rhs.get_section_by_section(lhs_section)
+ if rhs_section:
+ print 'comparing %s.%s...' % (lhs_section.segname, lhs_section.sectname),
+ sys.stdout.flush()
+ lhs_data = lhs_section.get_contents (self)
+ rhs_data = rhs_section.get_contents (rhs)
+ if lhs_data and rhs_data:
+ if lhs_data == rhs_data:
+ print 'ok'
+ else:
+ lhs_data_len = len(lhs_data)
+ rhs_data_len = len(rhs_data)
+ # if lhs_data_len < rhs_data_len:
+ # if lhs_data == rhs_data[0:lhs_data_len]:
+ # print 'section data for %s matches the first %u bytes' % (lhs_section.sectname, lhs_data_len)
+ # else:
+ # # TODO: check padding
+ # result = False
+ # elif lhs_data_len > rhs_data_len:
+ # if lhs_data[0:rhs_data_len] == rhs_data:
+ # print 'section data for %s matches the first %u bytes' % (lhs_section.sectname, lhs_data_len)
+ # else:
+ # # TODO: check padding
+ # result = False
+ # else:
+ result = False
+ print 'error: sections differ'
+ #print 'a) %s' % (lhs_section)
+ # dump_hex_byte_string_diff(0, lhs_data, rhs_data)
+ #print 'b) %s' % (rhs_section)
+ # dump_hex_byte_string_diff(0, rhs_data, lhs_data)
+ elif lhs_data and not rhs_data:
+ print 'error: section data missing from b:'
+ print 'a) %s' % (lhs_section)
+ print 'b) %s' % (rhs_section)
+ result = False
+ elif not lhs_data and rhs_data:
+ print 'error: section data missing from a:'
+ print 'a) %s' % (lhs_section)
+ print 'b) %s' % (rhs_section)
+ result = False
+ elif lhs_section.offset or rhs_section.offset:
+ print 'error: section data missing for both a and b:'
+ print 'a) %s' % (lhs_section)
+ print 'b) %s' % (rhs_section)
+ result = False
+ else:
+ print 'ok'
+ else:
+ result = False
+ print 'error: section %s is missing in %s' % (lhs_section.sectname, rhs.path)
+ else:
+ print 'error: comaparing a %s mach-o file with a %s mach-o file is not supported' % (self.type, rhs.type)
+ result = False
+ if not result:
+ print 'error: mach files differ'
+ return result
+ def dump_header(self, dump_description = True, options = None):
+ if options.verbose:
+ print "MAGIC CPU SUBTYPE FILETYPE NUM CMDS SIZE CMDS FLAGS"
+ print "---------- ---------- ---------- ---------- -------- ---------- ----------"
+ else:
+ print "MAGIC ARCH FILETYPE NUM CMDS SIZE CMDS FLAGS"
+ print "------------ ---------- -------------- -------- ---------- ----------"
+
+ def dump_flat(self, options):
+ if options.verbose:
+ print "%#8.8x %#8.8x %#8.8x %#8.8x %#8u %#8.8x %#8.8x" % (self.magic, self.arch.cpu , self.arch.sub, self.filetype.value, self.ncmds, self.sizeofcmds, self.flags.bits)
+ else:
+ print "%-12s %-10s %-14s %#8u %#8.8x %s" % (self.magic, self.arch, self.filetype, self.ncmds, self.sizeofcmds, self.flags)
+
+ def dump(self, options):
+ if options.dump_header:
+ self.dump_header(True, options)
+ if options.dump_load_commands:
+ self.dump_load_commands(False, options)
+ if options.dump_sections:
+ self.dump_sections(False, options)
+ if options.section_names:
+ self.dump_section_contents(options)
+ if options.dump_symtab:
+ self.get_symtab()
+ if len(self.symbols):
+ self.dump_sections(False, options)
+ else:
+ print "No symbols"
+ if options.find_mangled:
+ self.dump_symbol_names_matching_regex (re.compile('^_?_Z'))
+
+ def dump_header(self, dump_description = True, options = None):
+ if dump_description:
+ print self.description()
+ print "Mach Header"
+ print " magic: %#8.8x %s" % (self.magic.value, self.magic)
+ print " cputype: %#8.8x %s" % (self.arch.cpu, self.arch)
+ print " cpusubtype: %#8.8x" % self.arch.sub
+ print " filetype: %#8.8x %s" % (self.filetype.get_enum_value(), self.filetype.get_enum_name())
+ print " ncmds: %#8.8x %u" % (self.ncmds, self.ncmds)
+ print " sizeofcmds: %#8.8x" % self.sizeofcmds
+ print " flags: %#8.8x %s" % (self.flags.bits, self.flags)
+
+ def dump_load_commands(self, dump_description = True, options = None):
+ if dump_description:
+ print self.description()
+ for lc in self.commands:
+ print lc
+
+ def get_section_by_name (self, name):
+ for section in self.sections:
+ if section.sectname and section.sectname == name:
+ return section
+ return None
+
+ def get_section_by_section (self, other_section):
+ for section in self.sections:
+ if section.sectname == other_section.sectname and section.segname == other_section.segname:
+ return section
+ return None
+
+ def dump_sections(self, dump_description = True, options = None):
+ if dump_description:
+ print self.description()
+ num_sections = len(self.sections)
+ if num_sections > 1:
+ self.sections[1].dump_header()
+ for sect_idx in range(1,num_sections):
+ print "%s" % self.sections[sect_idx]
+
+ def dump_section_contents(self, options):
+ saved_section_to_disk = False
+ for sectname in options.section_names:
+ section = self.get_section_by_name(sectname)
+ if section:
+ sect_bytes = section.get_contents (self)
+ if options.outfile:
+ if not saved_section_to_disk:
+ outfile = open(options.outfile, 'w')
+ if options.extract_modules:
+ #print "Extracting modules from mach file..."
+ data = file_extract.FileExtract(StringIO.StringIO(sect_bytes), self.data.byte_order)
+ version = data.get_uint32()
+ num_modules = data.get_uint32()
+ #print "version = %u, num_modules = %u" % (version, num_modules)
+ for i in range(num_modules):
+ data_offset = data.get_uint64()
+ data_size = data.get_uint64()
+ name_offset = data.get_uint32()
+ language = data.get_uint32()
+ flags = data.get_uint32()
+ data.seek (name_offset)
+ module_name = data.get_c_string()
+ #print "module[%u] data_offset = %#16.16x, data_size = %#16.16x, name_offset = %#16.16x (%s), language = %u, flags = %#x" % (i, data_offset, data_size, name_offset, module_name, language, flags)
+ data.seek (data_offset)
+ outfile.write(data.read_size (data_size))
+ else:
+ print "Saving section %s to '%s'" % (sectname, options.outfile)
+ outfile.write(sect_bytes)
+ outfile.close()
+ saved_section_to_disk = True
+ else:
+ print "error: you can only save a single section to disk at a time, skipping section '%s'" % (sectname)
+ else:
+ print 'section %s:\n' % (sectname)
+ section.dump_header()
+ print '%s\n' % (section)
+ dump_memory (0, sect_bytes, options.max_count, 16)
+ else:
+ print 'error: no section named "%s" was found' % (sectname)
+
+ def get_segment(self, segname):
+ if len(self.segments) == 1 and self.segments[0].segname == '':
+ return self.segments[0]
+ for segment in self.segments:
+ if segment.segname == segname:
+ return segment
+ return None
+
+ def get_first_load_command(self, lc_enum_value):
+ for lc in self.commands:
+ if lc.command.value == lc_enum_value:
+ return lc
+ return None
+
+ def get_symtab(self):
+ if self.data and not self.symbols:
+ lc_symtab = self.get_first_load_command (LC_SYMTAB)
+ if lc_symtab:
+ symtab_offset = self.file_off
+ if self.data.is_in_memory():
+ linkedit_segment = self.get_segment('__LINKEDIT')
+ if linkedit_segment:
+ linkedit_vmaddr = linkedit_segment.vmaddr
+ linkedit_fileoff = linkedit_segment.fileoff
+ symtab_offset = linkedit_vmaddr + lc_symtab.symoff - linkedit_fileoff
+ symtab_offset = linkedit_vmaddr + lc_symtab.stroff - linkedit_fileoff
+ else:
+ symtab_offset += lc_symtab.symoff
+
+ self.data.seek (symtab_offset)
+ is_64 = self.is_64_bit()
+ for i in range(lc_symtab.nsyms):
+ nlist = Mach.NList()
+ nlist.unpack (self, self.data, lc_symtab)
+ self.symbols.append(nlist)
+ else:
+ print "no LC_SYMTAB"
+
+ def dump_symtab(self, dump_description = True, options = None):
+ self.get_symtab()
+ if dump_description:
+ print self.description()
+ for i, symbol in enumerate(self.symbols):
+ print '[%5u] %s' % (i, symbol)
+
+ def dump_symbol_names_matching_regex(self, regex, file=None):
+ self.get_symtab()
+ for symbol in self.symbols:
+ if symbol.name and regex.search (symbol.name):
+ print symbol.name
+ if file:
+ file.write('%s\n' % (symbol.name))
+
+ def is_64_bit(self):
+ return self.magic.is_64_bit()
+
+ class LoadCommand:
+ class Command(dict_utils.Enum):
+ enum = {
+ 'LC_SEGMENT' : LC_SEGMENT,
+ 'LC_SYMTAB' : LC_SYMTAB,
+ 'LC_SYMSEG' : LC_SYMSEG,
+ 'LC_THREAD' : LC_THREAD,
+ 'LC_UNIXTHREAD' : LC_UNIXTHREAD,
+ 'LC_LOADFVMLIB' : LC_LOADFVMLIB,
+ 'LC_IDFVMLIB' : LC_IDFVMLIB,
+ 'LC_IDENT' : LC_IDENT,
+ 'LC_FVMFILE' : LC_FVMFILE,
+ 'LC_PREPAGE' : LC_PREPAGE,
+ 'LC_DYSYMTAB' : LC_DYSYMTAB,
+ 'LC_LOAD_DYLIB' : LC_LOAD_DYLIB,
+ 'LC_ID_DYLIB' : LC_ID_DYLIB,
+ 'LC_LOAD_DYLINKER' : LC_LOAD_DYLINKER,
+ 'LC_ID_DYLINKER' : LC_ID_DYLINKER,
+ 'LC_PREBOUND_DYLIB' : LC_PREBOUND_DYLIB,
+ 'LC_ROUTINES' : LC_ROUTINES,
+ 'LC_SUB_FRAMEWORK' : LC_SUB_FRAMEWORK,
+ 'LC_SUB_UMBRELLA' : LC_SUB_UMBRELLA,
+ 'LC_SUB_CLIENT' : LC_SUB_CLIENT,
+ 'LC_SUB_LIBRARY' : LC_SUB_LIBRARY,
+ 'LC_TWOLEVEL_HINTS' : LC_TWOLEVEL_HINTS,
+ 'LC_PREBIND_CKSUM' : LC_PREBIND_CKSUM,
+ 'LC_LOAD_WEAK_DYLIB' : LC_LOAD_WEAK_DYLIB,
+ 'LC_SEGMENT_64' : LC_SEGMENT_64,
+ 'LC_ROUTINES_64' : LC_ROUTINES_64,
+ 'LC_UUID' : LC_UUID,
+ 'LC_RPATH' : LC_RPATH,
+ 'LC_CODE_SIGNATURE' : LC_CODE_SIGNATURE,
+ 'LC_SEGMENT_SPLIT_INFO' : LC_SEGMENT_SPLIT_INFO,
+ 'LC_REEXPORT_DYLIB' : LC_REEXPORT_DYLIB,
+ 'LC_LAZY_LOAD_DYLIB' : LC_LAZY_LOAD_DYLIB,
+ 'LC_ENCRYPTION_INFO' : LC_ENCRYPTION_INFO,
+ 'LC_DYLD_INFO' : LC_DYLD_INFO,
+ 'LC_DYLD_INFO_ONLY' : LC_DYLD_INFO_ONLY,
+ 'LC_LOAD_UPWARD_DYLIB' : LC_LOAD_UPWARD_DYLIB,
+ 'LC_VERSION_MIN_MACOSX' : LC_VERSION_MIN_MACOSX,
+ 'LC_VERSION_MIN_IPHONEOS' : LC_VERSION_MIN_IPHONEOS,
+ 'LC_FUNCTION_STARTS' : LC_FUNCTION_STARTS,
+ 'LC_DYLD_ENVIRONMENT' : LC_DYLD_ENVIRONMENT
+ }
+
+ def __init__(self, initial_value = 0):
+ dict_utils.Enum.__init__(self, initial_value, self.enum)
+
+
+ def __init__(self, c=None, l=0,o=0):
+ if c != None:
+ self.command = c
+ else:
+ self.command = Mach.LoadCommand.Command(0)
+ self.length = l
+ self.file_off = o
+
+ def unpack(self, mach_file, data):
+ self.file_off = data.tell()
+ self.command.value, self.length = data.get_n_uint32(2)
+
+ def skip(self, data):
+ data.seek (self.file_off + self.length, 0)
+
+ def __str__(self):
+ lc_name = self.command.get_enum_name()
+ return '%#8.8x: <%#4.4x> %-24s' % (self.file_off, self.length, lc_name)
+
+ class Section:
+
+ def __init__(self):
+ self.index = 0
+ self.is_64 = False
+ self.sectname = None
+ self.segname = None
+ self.addr = 0
+ self.size = 0
+ self.offset = 0
+ self.align = 0
+ self.reloff = 0
+ self.nreloc = 0
+ self.flags = 0
+ self.reserved1 = 0
+ self.reserved2 = 0
+ self.reserved3 = 0
+
+ def unpack(self, is_64, data):
+ self.is_64 = is_64
+ self.sectname = data.get_fixed_length_c_string (16, '', True)
+ self.segname = data.get_fixed_length_c_string (16, '', True)
+ if self.is_64:
+ self.addr, self.size = data.get_n_uint64(2)
+ self.offset, self.align, self.reloff, self.nreloc, self.flags, self.reserved1, self.reserved2, self.reserved3 = data.get_n_uint32(8)
+ else:
+ self.addr, self.size = data.get_n_uint32(2)
+ self.offset, self.align, self.reloff, self.nreloc, self.flags, self.reserved1, self.reserved2 = data.get_n_uint32(7)
+
+ def dump_header(self):
+ if self.is_64:
+ print "INDEX ADDRESS SIZE OFFSET ALIGN RELOFF NRELOC FLAGS RESERVED1 RESERVED2 RESERVED3 NAME";
+ print "===== ------------------ ------------------ ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ----------------------";
+ else:
+ print "INDEX ADDRESS SIZE OFFSET ALIGN RELOFF NRELOC FLAGS RESERVED1 RESERVED2 NAME";
+ print "===== ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ----------------------";
+
+ def __str__(self):
+ if self.is_64:
+ return "[%3u] %#16.16x %#16.16x %#8.8x %#8.8x %#8.8x %#8.8x %#8.8x %#8.8x %#8.8x %#8.8x %s.%s" % (self.index, self.addr, self.size, self.offset, self.align, self.reloff, self.nreloc, self.flags, self.reserved1, self.reserved2, self.reserved3, self.segname, self.sectname)
+ else:
+ return "[%3u] %#8.8x %#8.8x %#8.8x %#8.8x %#8.8x %#8.8x %#8.8x %#8.8x %#8.8x %s.%s" % (self.index, self.addr, self.size, self.offset, self.align, self.reloff, self.nreloc, self.flags, self.reserved1, self.reserved2, self.segname, self.sectname)
+
+ def get_contents(self, mach_file):
+ '''Get the section contents as a python string'''
+ if self.size > 0 and mach_file.get_segment(self.segname).filesize > 0:
+ data = mach_file.get_data()
+ if data:
+ section_data_offset = mach_file.file_off + self.offset
+ #print '%s.%s is at offset 0x%x with size 0x%x' % (self.segname, self.sectname, section_data_offset, self.size)
+ data.push_offset_and_seek (section_data_offset)
+ bytes = data.read_size(self.size)
+ data.pop_offset_and_seek()
+ return bytes
+ return None
+
+ class DylibLoadCommand(LoadCommand):
+ def __init__(self, lc):
+ Mach.LoadCommand.__init__(self, lc.command, lc.length, lc.file_off)
+ self.name = None
+ self.timestamp = 0
+ self.current_version = 0
+ self.compatibility_version = 0
+
+ def unpack(self, mach_file, data):
+ byte_order_char = mach_file.magic.get_byte_order()
+ name_offset, self.timestamp, self.current_version, self.compatibility_version = data.get_n_uint32(4)
+ data.seek(self.file_off + name_offset, 0)
+ self.name = data.get_fixed_length_c_string(self.length - 24)
+
+ def __str__(self):
+ s = Mach.LoadCommand.__str__(self);
+ s += "%#8.8x %#8.8x %#8.8x " % (self.timestamp, self.current_version, self.compatibility_version)
+ s += self.name
+ return s
+
+ class LoadDYLDLoadCommand(LoadCommand):
+ def __init__(self, lc):
+ Mach.LoadCommand.__init__(self, lc.command, lc.length, lc.file_off)
+ self.name = None
+
+ def unpack(self, mach_file, data):
+ data.get_uint32()
+ self.name = data.get_fixed_length_c_string(self.length - 12)
+
+ def __str__(self):
+ s = Mach.LoadCommand.__str__(self);
+ s += "%s" % self.name
+ return s
+
+ class UnixThreadLoadCommand(LoadCommand):
+ class ThreadState:
+ def __init__(self):
+ self.flavor = 0
+ self.count = 0
+ self.register_values = list()
+
+ def unpack(self, data):
+ self.flavor, self.count = data.get_n_uint32(2)
+ self.register_values = data.get_n_uint32(self.count)
+
+ def __str__(self):
+ s = "flavor = %u, count = %u, regs =" % (self.flavor, self.count)
+ i = 0
+ for register_value in self.register_values:
+ if i % 8 == 0:
+ s += "\n "
+ s += " %#8.8x" % register_value
+ i += 1
+ return s
+
+ def __init__(self, lc):
+ Mach.LoadCommand.__init__(self, lc.command, lc.length, lc.file_off)
+ self.reg_sets = list()
+
+ def unpack(self, mach_file, data):
+ reg_set = Mach.UnixThreadLoadCommand.ThreadState()
+ reg_set.unpack (data)
+ self.reg_sets.append(reg_set)
+
+ def __str__(self):
+ s = Mach.LoadCommand.__str__(self);
+ for reg_set in self.reg_sets:
+ s += "%s" % reg_set
+ return s
+
+ class DYLDInfoOnlyLoadCommand(LoadCommand):
+ def __init__(self, lc):
+ Mach.LoadCommand.__init__(self, lc.command, lc.length, lc.file_off)
+ self.rebase_off = 0
+ self.rebase_size = 0
+ self.bind_off = 0
+ self.bind_size = 0
+ self.weak_bind_off = 0
+ self.weak_bind_size = 0
+ self.lazy_bind_off = 0
+ self.lazy_bind_size = 0
+ self.export_off = 0
+ self.export_size = 0
+
+ def unpack(self, mach_file, data):
+ byte_order_char = mach_file.magic.get_byte_order()
+ self.rebase_off, self.rebase_size, self.bind_off, self.bind_size, self.weak_bind_off, self.weak_bind_size, self.lazy_bind_off, self.lazy_bind_size, self.export_off, self.export_size = data.get_n_uint32(10)
+
+ def __str__(self):
+ s = Mach.LoadCommand.__str__(self);
+ s += "rebase_off = %#8.8x, rebase_size = %u, " % (self.rebase_off, self.rebase_size)
+ s += "bind_off = %#8.8x, bind_size = %u, " % (self.bind_off, self.bind_size)
+ s += "weak_bind_off = %#8.8x, weak_bind_size = %u, " % (self.weak_bind_off, self.weak_bind_size)
+ s += "lazy_bind_off = %#8.8x, lazy_bind_size = %u, " % (self.lazy_bind_off, self.lazy_bind_size)
+ s += "export_off = %#8.8x, export_size = %u, " % (self.export_off, self.export_size)
+ return s
+
+ class DYLDSymtabLoadCommand(LoadCommand):
+ def __init__(self, lc):
+ Mach.LoadCommand.__init__(self, lc.command, lc.length, lc.file_off)
+ self.ilocalsym = 0
+ self.nlocalsym = 0
+ self.iextdefsym = 0
+ self.nextdefsym = 0
+ self.iundefsym = 0
+ self.nundefsym = 0
+ self.tocoff = 0
+ self.ntoc = 0
+ self.modtaboff = 0
+ self.nmodtab = 0
+ self.extrefsymoff = 0
+ self.nextrefsyms = 0
+ self.indirectsymoff = 0
+ self.nindirectsyms = 0
+ self.extreloff = 0
+ self.nextrel = 0
+ self.locreloff = 0
+ self.nlocrel = 0
+
+ def unpack(self, mach_file, data):
+ byte_order_char = mach_file.magic.get_byte_order()
+ self.ilocalsym, self.nlocalsym, self.iextdefsym, self.nextdefsym, self.iundefsym, self.nundefsym, self.tocoff, self.ntoc, self.modtaboff, self.nmodtab, self.extrefsymoff, self.nextrefsyms, self.indirectsymoff, self.nindirectsyms, self.extreloff, self.nextrel, self.locreloff, self.nlocrel = data.get_n_uint32(18)
+
+ def __str__(self):
+ s = Mach.LoadCommand.__str__(self);
+ # s += "ilocalsym = %u, nlocalsym = %u, " % (self.ilocalsym, self.nlocalsym)
+ # s += "iextdefsym = %u, nextdefsym = %u, " % (self.iextdefsym, self.nextdefsym)
+ # s += "iundefsym %u, nundefsym = %u, " % (self.iundefsym, self.nundefsym)
+ # s += "tocoff = %#8.8x, ntoc = %u, " % (self.tocoff, self.ntoc)
+ # s += "modtaboff = %#8.8x, nmodtab = %u, " % (self.modtaboff, self.nmodtab)
+ # s += "extrefsymoff = %#8.8x, nextrefsyms = %u, " % (self.extrefsymoff, self.nextrefsyms)
+ # s += "indirectsymoff = %#8.8x, nindirectsyms = %u, " % (self.indirectsymoff, self.nindirectsyms)
+ # s += "extreloff = %#8.8x, nextrel = %u, " % (self.extreloff, self.nextrel)
+ # s += "locreloff = %#8.8x, nlocrel = %u" % (self.locreloff, self.nlocrel)
+ s += "ilocalsym = %-10u, nlocalsym = %u\n" % (self.ilocalsym, self.nlocalsym)
+ s += " iextdefsym = %-10u, nextdefsym = %u\n" % (self.iextdefsym, self.nextdefsym)
+ s += " iundefsym = %-10u, nundefsym = %u\n" % (self.iundefsym, self.nundefsym)
+ s += " tocoff = %#8.8x, ntoc = %u\n" % (self.tocoff, self.ntoc)
+ s += " modtaboff = %#8.8x, nmodtab = %u\n" % (self.modtaboff, self.nmodtab)
+ s += " extrefsymoff = %#8.8x, nextrefsyms = %u\n" % (self.extrefsymoff, self.nextrefsyms)
+ s += " indirectsymoff = %#8.8x, nindirectsyms = %u\n" % (self.indirectsymoff, self.nindirectsyms)
+ s += " extreloff = %#8.8x, nextrel = %u\n" % (self.extreloff, self.nextrel)
+ s += " locreloff = %#8.8x, nlocrel = %u" % (self.locreloff, self.nlocrel)
+ return s
+
+ class SymtabLoadCommand(LoadCommand):
+ def __init__(self, lc):
+ Mach.LoadCommand.__init__(self, lc.command, lc.length, lc.file_off)
+ self.symoff = 0
+ self.nsyms = 0
+ self.stroff = 0
+ self.strsize = 0
+
+ def unpack(self, mach_file, data):
+ byte_order_char = mach_file.magic.get_byte_order()
+ self.symoff, self.nsyms, self.stroff, self.strsize = data.get_n_uint32(4)
+
+ def __str__(self):
+ s = Mach.LoadCommand.__str__(self);
+ s += "symoff = %#8.8x, nsyms = %u, stroff = %#8.8x, strsize = %u" % (self.symoff, self.nsyms, self.stroff, self.strsize)
+ return s
+
+
+ class UUIDLoadCommand(LoadCommand):
+ def __init__(self, lc):
+ Mach.LoadCommand.__init__(self, lc.command, lc.length, lc.file_off)
+ self.uuid = None
+
+ def unpack(self, mach_file, data):
+ uuid_data = data.get_n_uint8(16)
+ uuid_str = ''
+ for byte in uuid_data:
+ uuid_str += '%2.2x' % byte
+ self.uuid = uuid.UUID(uuid_str)
+ mach_file.uuid = self.uuid
+
+ def __str__(self):
+ s = Mach.LoadCommand.__str__(self);
+ s += self.uuid.__str__()
+ return s
+
+ class DataBlobLoadCommand(LoadCommand):
+ def __init__(self, lc):
+ Mach.LoadCommand.__init__(self, lc.command, lc.length, lc.file_off)
+ self.dataoff = 0
+ self.datasize = 0
+
+ def unpack(self, mach_file, data):
+ byte_order_char = mach_file.magic.get_byte_order()
+ self.dataoff, self.datasize = data.get_n_uint32(2)
+
+ def __str__(self):
+ s = Mach.LoadCommand.__str__(self);
+ s += "dataoff = %#8.8x, datasize = %u" % (self.dataoff, self.datasize)
+ return s
+
+ class EncryptionInfoLoadCommand(LoadCommand):
+ def __init__(self, lc):
+ Mach.LoadCommand.__init__(self, lc.command, lc.length, lc.file_off)
+ self.cryptoff = 0
+ self.cryptsize = 0
+ self.cryptid = 0
+
+ def unpack(self, mach_file, data):
+ byte_order_char = mach_file.magic.get_byte_order()
+ self.cryptoff, self.cryptsize, self.cryptid = data.get_n_uint32(3)
+
+ def __str__(self):
+ s = Mach.LoadCommand.__str__(self);
+ s += "file-range = [%#8.8x - %#8.8x), cryptsize = %u, cryptid = %u" % (self.cryptoff, self.cryptoff + self.cryptsize, self.cryptsize, self.cryptid)
+ return s
+
+ class SegmentLoadCommand(LoadCommand):
+
+ def __init__(self, lc):
+ Mach.LoadCommand.__init__(self, lc.command, lc.length, lc.file_off)
+ self.segname = None
+ self.vmaddr = 0
+ self.vmsize = 0
+ self.fileoff = 0
+ self.filesize = 0
+ self.maxprot = 0
+ self.initprot = 0
+ self.nsects = 0
+ self.flags = 0
+
+ def unpack(self, mach_file, data):
+ is_64 = self.command.get_enum_value() == LC_SEGMENT_64;
+ self.segname = data.get_fixed_length_c_string (16, '', True)
+ if is_64:
+ self.vmaddr, self.vmsize, self.fileoff, self.filesize = data.get_n_uint64(4)
+ else:
+ self.vmaddr, self.vmsize, self.fileoff, self.filesize = data.get_n_uint32(4)
+ self.maxprot, self.initprot, self.nsects, self.flags = data.get_n_uint32(4)
+ mach_file.segments.append(self)
+ for i in range(self.nsects):
+ section = Mach.Section()
+ section.unpack(is_64, data)
+ section.index = len (mach_file.sections)
+ mach_file.sections.append(section)
+
+
+ def __str__(self):
+ s = Mach.LoadCommand.__str__(self);
+ if self.command.get_enum_value() == LC_SEGMENT:
+ s += "%#8.8x %#8.8x %#8.8x %#8.8x " % (self.vmaddr, self.vmsize, self.fileoff, self.filesize)
+ else:
+ s += "%#16.16x %#16.16x %#16.16x %#16.16x " % (self.vmaddr, self.vmsize, self.fileoff, self.filesize)
+ s += "%s %s %3u %#8.8x" % (vm_prot_names[self.maxprot], vm_prot_names[self.initprot], self.nsects, self.flags)
+ s += ' ' + self.segname
+ return s
+
+ class NList:
+ class Type:
+ class Stab(dict_utils.Enum):
+ enum = {
+ 'N_GSYM' : N_GSYM ,
+ 'N_FNAME' : N_FNAME ,
+ 'N_FUN' : N_FUN ,
+ 'N_STSYM' : N_STSYM ,
+ 'N_LCSYM' : N_LCSYM ,
+ 'N_BNSYM' : N_BNSYM ,
+ 'N_OPT' : N_OPT ,
+ 'N_RSYM' : N_RSYM ,
+ 'N_SLINE' : N_SLINE ,
+ 'N_ENSYM' : N_ENSYM ,
+ 'N_SSYM' : N_SSYM ,
+ 'N_SO' : N_SO ,
+ 'N_OSO' : N_OSO ,
+ 'N_LSYM' : N_LSYM ,
+ 'N_BINCL' : N_BINCL ,
+ 'N_SOL' : N_SOL ,
+ 'N_PARAMS' : N_PARAMS ,
+ 'N_VERSION' : N_VERSION ,
+ 'N_OLEVEL' : N_OLEVEL ,
+ 'N_PSYM' : N_PSYM ,
+ 'N_EINCL' : N_EINCL ,
+ 'N_ENTRY' : N_ENTRY ,
+ 'N_LBRAC' : N_LBRAC ,
+ 'N_EXCL' : N_EXCL ,
+ 'N_RBRAC' : N_RBRAC ,
+ 'N_BCOMM' : N_BCOMM ,
+ 'N_ECOMM' : N_ECOMM ,
+ 'N_ECOML' : N_ECOML ,
+ 'N_LENG' : N_LENG
+ }
+
+ def __init__(self, magic = 0):
+ dict_utils.Enum.__init__(self, magic, self.enum)
+
+ def __init__(self, t = 0):
+ self.value = t
+
+ def __str__(self):
+ n_type = self.value
+ if n_type & N_STAB:
+ stab = Mach.NList.Type.Stab(self.value)
+ return '%s' % stab
+ else:
+ type = self.value & N_TYPE
+ type_str = ''
+ if type == N_UNDF:
+ type_str = 'N_UNDF'
+ elif type == N_ABS:
+ type_str = 'N_ABS '
+ elif type == N_SECT:
+ type_str = 'N_SECT'
+ elif type == N_PBUD:
+ type_str = 'N_PBUD'
+ elif type == N_INDR:
+ type_str = 'N_INDR'
+ else:
+ type_str = "??? (%#2.2x)" % type
+ if n_type & N_PEXT:
+ type_str += ' | PEXT'
+ if n_type & N_EXT:
+ type_str += ' | EXT '
+ return type_str
+
+
+ def __init__(self):
+ self.index = 0
+ self.name_offset = 0
+ self.name = 0
+ self.type = Mach.NList.Type()
+ self.sect_idx = 0
+ self.desc = 0
+ self.value = 0
+
+ def unpack(self, mach_file, data, symtab_lc):
+ self.index = len(mach_file.symbols)
+ self.name_offset = data.get_uint32()
+ self.type.value, self.sect_idx = data.get_n_uint8(2)
+ self.desc = data.get_uint16()
+ if mach_file.is_64_bit():
+ self.value = data.get_uint64()
+ else:
+ self.value = data.get_uint32()
+ data.push_offset_and_seek (mach_file.file_off + symtab_lc.stroff + self.name_offset)
+ #print "get string for symbol[%u]" % self.index
+ self.name = data.get_c_string()
+ data.pop_offset_and_seek()
+
+ def __str__(self):
+ name_display = ''
+ if len(self.name):
+ name_display = ' "%s"' % self.name
+ return '%#8.8x %#2.2x (%-20s) %#2.2x %#4.4x %16.16x%s' % (self.name_offset, self.type.value, self.type, self.sect_idx, self.desc, self.value, name_display)
+
+
+ class Interactive(cmd.Cmd):
+ '''Interactive command interpreter to mach-o files.'''
+
+ def __init__(self, mach, options):
+ cmd.Cmd.__init__(self)
+ self.intro = 'Interactive mach-o command interpreter'
+ self.prompt = 'mach-o: %s %% ' % mach.path
+ self.mach = mach
+ self.options = options
+
+ def default(self, line):
+ '''Catch all for unknown command, which will exit the interpreter.'''
+ print "uknown command: %s" % line
+ return True
+
+ def do_q(self, line):
+ '''Quit command'''
+ return True
+
+ def do_quit(self, line):
+ '''Quit command'''
+ return True
+
+ def do_header(self, line):
+ '''Dump mach-o file headers'''
+ self.mach.dump_header(True, self.options)
+ return False
+
+ def do_load(self, line):
+ '''Dump all mach-o load commands'''
+ self.mach.dump_load_commands(True, self.options)
+ return False
+
+ def do_sections(self, line):
+ '''Dump all mach-o sections'''
+ self.mach.dump_sections(True, self.options)
+ return False
+
+ def do_symtab(self, line):
+ '''Dump all mach-o symbols in the symbol table'''
+ self.mach.dump_symtab(True, self.options)
+ return False
+
+if __name__ == '__main__':
+ parser = optparse.OptionParser(description='A script that parses skinny and universal mach-o files.')
+ parser.add_option('--arch', '-a', type='string', metavar='arch', dest='archs', action='append', help='specify one or more architectures by name')
+ parser.add_option('-v', '--verbose', action='store_true', dest='verbose', help='display verbose debug info', default=False)
+ parser.add_option('-H', '--header', action='store_true', dest='dump_header', help='dump the mach-o file header', default=False)
+ parser.add_option('-l', '--load-commands', action='store_true', dest='dump_load_commands', help='dump the mach-o load commands', default=False)
+ parser.add_option('-s', '--symtab', action='store_true', dest='dump_symtab', help='dump the mach-o symbol table', default=False)
+ parser.add_option('-S', '--sections', action='store_true', dest='dump_sections', help='dump the mach-o sections', default=False)
+ parser.add_option('--section', type='string', metavar='sectname', dest='section_names', action='append', help='Specify one or more section names to dump', default=[])
+ parser.add_option('-o', '--out', type='string', dest='outfile', help='Used in conjunction with the --section=NAME option to save a single section\'s data to disk.', default=False)
+ parser.add_option('-i', '--interactive', action='store_true', dest='interactive', help='enable interactive mode', default=False)
+ parser.add_option('-m', '--mangled', action='store_true', dest='find_mangled', help='dump all mangled names in a mach file', default=False)
+ parser.add_option('-c', '--compare', action='store_true', dest='compare', help='compare two mach files', default=False)
+ parser.add_option('-M', '--extract-modules', action='store_true', dest='extract_modules', help='Extract modules from file', default=False)
+ parser.add_option('-C', '--count', type='int', dest='max_count', help='Sets the max byte count when dumping section data', default=-1)
+
+ (options, mach_files) = parser.parse_args()
+ if options.extract_modules:
+ if options.section_names:
+ print "error: can't use --section option with the --extract-modules option"
+ exit(1)
+ if not options.outfile:
+ print "error: the --output=FILE option must be specified with the --extract-modules option"
+ exit(1)
+ options.section_names.append("__apple_ast")
+ if options.compare:
+ if len(mach_files) == 2:
+ mach_a = Mach()
+ mach_b = Mach()
+ mach_a.parse(mach_files[0])
+ mach_b.parse(mach_files[1])
+ mach_a.compare(mach_b)
+ else:
+ print 'error: --compare takes two mach files as arguments'
+ else:
+ if not (options.dump_header or options.dump_load_commands or options.dump_symtab or options.dump_sections or options.find_mangled or options.section_names):
+ options.dump_header = True
+ options.dump_load_commands = True
+ if options.verbose:
+ print 'options', options
+ print 'mach_files', mach_files
+ for path in mach_files:
+ mach = Mach()
+ mach.parse(path)
+ if options.interactive:
+ interpreter = Mach.Interactive(mach, options)
+ interpreter.cmdloop()
+ else:
+ mach.dump(options)
+
diff --git a/examples/python/memory.py b/examples/python/memory.py
new file mode 100755
index 0000000000000..ae78e24e2e29c
--- /dev/null
+++ b/examples/python/memory.py
@@ -0,0 +1,181 @@
+#!/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
+#----------------------------------------------------------------------
+
+import commands
+import platform
+import os
+import re
+import sys
+
+try:
+ # Just try for LLDB in case PYTHONPATH is already correctly setup
+ import lldb
+except ImportError:
+ lldb_python_dirs = list()
+ # lldb is not in the PYTHONPATH, try some defaults for the current platform
+ platform_system = platform.system()
+ if platform_system == 'Darwin':
+ # 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')
+ 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:
+ import lldb
+ except ImportError:
+ pass
+ else:
+ print 'imported lldb from: "%s"' % (lldb_python_dir)
+ success = True
+ break
+ if not success:
+ print "error: couldn't locate the 'lldb' module, please set PYTHONPATH correctly"
+ sys.exit(1)
+
+import commands
+import optparse
+import shlex
+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)
+ if opt_str == "--uint16":
+ int16 = int(value, 0)
+ parser.values.data += struct.pack('1H',int16)
+ if opt_str == "--uint32":
+ int32 = int(value, 0)
+ parser.values.data += struct.pack('1I',int32)
+ if opt_str == "--uint64":
+ int64 = int(value, 0)
+ parser.values.data += struct.pack('1Q',int64)
+ if opt_str == "--int8":
+ int8 = int(value, 0)
+ parser.values.data += struct.pack('1b',int8)
+ if opt_str == "--int16":
+ int16 = int(value, 0)
+ parser.values.data += struct.pack('1h',int16)
+ if opt_str == "--int32":
+ int32 = int(value, 0)
+ parser.values.data += struct.pack('1i',int32)
+ if opt_str == "--int64":
+ int64 = int(value, 0)
+ 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.
+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='')
+ return parser
+
+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()
+ (options, args) = parser.parse_args(command_args)
+ # 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.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)
+
+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):
+ 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)
+ 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)
+ 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)
+ return
+ options.size = end_addr - start_addr
+ else:
+ 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
+ process = target.process
+ if not process:
+ print >>result, 'error: invalid process'
+ return
+
+ error = lldb.SBError()
+ 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),
+ 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)
+ 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')
+ print '"memfind" command installed, use the "--help" option for detailed help'
diff --git a/examples/python/operating_system.py b/examples/python/operating_system.py
new file mode 100644
index 0000000000000..49cd5ff34398e
--- /dev/null
+++ b/examples/python/operating_system.py
@@ -0,0 +1,104 @@
+#!/usr/bin/python
+
+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():
+ self.process = process
+ 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
+ # correct thing to use for this plug-in.
+ return self.process.target
+
+ def create_thread(self, tid, context):
+ if tid == 0x444444444:
+ 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
+ # tid => thread ID (mandatory)
+ # name => thread name (optional key/value pair)
+ # queue => thread dispatch queue name (optional key/value pair)
+ # state => thred state (mandatory, set to 'stopped' for now)
+ # stop_reason => thread stop reason. (mandatory, usually set to 'none')
+ # Possible values include:
+ # 'breakpoint' if the thread is stopped at a breakpoint
+ # 'none' thread is just stopped because the process is stopped
+ # 'trace' the thread just single stepped
+ # The usual value for this while threads are in memory is 'none'
+ # register_data_addr => the address of the register data in memory (optional key/value pair)
+ # 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 }
+ ]
+ return self.threads
+
+ def get_register_info(self):
+ if self.registers == 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 },
+ ]
+ 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);
+ 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);
+ 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);
+ 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);
+ 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 None
+
diff --git a/examples/python/performance.py b/examples/python/performance.py
new file mode 100755
index 0000000000000..a225d7b731e07
--- /dev/null
+++ b/examples/python/performance.py
@@ -0,0 +1,335 @@
+#!/usr/bin/python
+
+#----------------------------------------------------------------------
+# Be sure to add the python path that points to the LLDB shared library.
+# On MacOSX csh, tcsh:
+# setenv PYTHONPATH /Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Resources/Python
+# On MacOSX sh, bash:
+# export PYTHONPATH=/Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Resources/Python
+#----------------------------------------------------------------------
+
+import commands
+import optparse
+import os
+import platform
+import re
+import resource
+import sys
+import time
+import types
+
+#----------------------------------------------------------------------
+# Code that auto imports LLDB
+#----------------------------------------------------------------------
+try:
+ # Just try for LLDB in case PYTHONPATH is already correctly setup
+ import lldb
+except ImportError:
+ lldb_python_dirs = list()
+ # lldb is not in the PYTHONPATH, try some defaults for the current platform
+ platform_system = platform.system()
+ if platform_system == 'Darwin':
+ # 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')
+ 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:
+ import lldb
+ except ImportError:
+ pass
+ else:
+ print 'imported lldb from: "%s"' % (lldb_python_dir)
+ success = True
+ break
+ if not success:
+ print "error: couldn't locate the 'lldb' module, please set PYTHONPATH correctly"
+ sys.exit(1)
+
+
+class Timer:
+ def __enter__(self):
+ self.start = time.clock()
+ return self
+
+ def __exit__(self, *args):
+ 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):
+ self.callback = callback
+ self.callback_owner = callback_owner
+ 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):
+ Action.__init__(self, callback, callback_owner)
+ def ThreadStopped (self, thread):
+ if thread.GetStopReason() == lldb.eStopReasonPlanComplete:
+ if self.callback:
+ if self.callback_owner:
+ self.callback (self.callback_owner, thread)
+ else:
+ 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):
+ Action.__init__(self, callback, callback_owner)
+ self.modules = lldb.SBFileSpecList()
+ self.files = lldb.SBFileSpecList()
+ self.breakpoints = list()
+ # "module" can be a list or a string
+ if breakpoint:
+ self.breakpoints.append(breakpoint)
+ else:
+ if module:
+ if isinstance(module, types.ListType):
+ for module_path in module:
+ self.modules.Append(lldb.SBFileSpec(module_path, False))
+ elif isinstance(module, types.StringTypes):
+ self.modules.Append(lldb.SBFileSpec(module, False))
+ if name:
+ # "file" can be a list or a string
+ if file:
+ if isinstance(file, types.ListType):
+ self.files = lldb.SBFileSpecList()
+ for f in file:
+ 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))
+ elif file and line:
+ 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)
+ else:
+ 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()
+ self.target = None
+ self.process = None
+ self.thread = None
+ self.launch_info = None
+ self.done = False
+ self.listener = self.debugger.GetListener()
+ 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):
+ 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)
+ if not error.Success():
+ print "error: %s" % error.GetCString()
+ if self.process:
+ self.process.GetBroadcaster().AddListener(self.listener, lldb.SBProcess.eBroadcastBitStateChanged | lldb.SBProcess.eBroadcastBitInterrupt)
+ return True
+ return False
+
+ 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.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:
+ 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:
+ continue
+ elif state == lldb.eStateStopped:
+ event = process_event
+ call_test_step = True
+ fatal = False
+ selected_thread = False
+ 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()),
+ if stop_reason == lldb.eStopReasonNone:
+ if self.verbose:
+ print "none"
+ elif stop_reason == lldb.eStopReasonTrace:
+ select_thread = True
+ if self.verbose:
+ print "trace"
+ elif stop_reason == lldb.eStopReasonPlanComplete:
+ select_thread = True
+ if self.verbose:
+ print "plan complete"
+ elif stop_reason == lldb.eStopReasonThreadExiting:
+ if self.verbose:
+ print "thread exiting"
+ elif stop_reason == lldb.eStopReasonExec:
+ if self.verbose:
+ print "exec"
+ elif stop_reason == lldb.eStopReasonInvalid:
+ if self.verbose:
+ print "invalid"
+ elif stop_reason == lldb.eStopReasonException:
+ select_thread = True
+ if self.verbose:
+ print "exception"
+ fatal = True
+ elif stop_reason == lldb.eStopReasonBreakpoint:
+ select_thread = True
+ bp_id = thread.GetStopReasonDataAtIndex(0)
+ bp_loc_id = thread.GetStopReasonDataAtIndex(1)
+ if self.verbose:
+ print "breakpoint id = %d.%d" % (bp_id, bp_loc_id)
+ elif stop_reason == lldb.eStopReasonWatchpoint:
+ select_thread = True
+ if self.verbose:
+ print "watchpoint id = %d" % (thread.GetStopReasonDataAtIndex(0))
+ elif stop_reason == lldb.eStopReasonSignal:
+ 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)
+
+ for action in self.user_actions:
+ action.ThreadStopped (thread)
+
+
+ if fatal:
+ # 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.value = dict()
+
+ def Measure(self):
+ output = commands.getoutput(self.command).split("\n")[-1]
+ values = re.split('[-+\s]+', output)
+ for (idx, stat) in enumerate(values):
+ multiplier = 1
+ if stat:
+ if stat[-1] == 'K':
+ multiplier = 1024
+ stat = stat[:-1]
+ elif stat[-1] == 'M':
+ multiplier = 1024*1024
+ stat = stat[:-1]
+ elif stat[-1] == 'G':
+ multiplier = 1024*1024*1024
+ elif stat[-1] == 'T':
+ multiplier = 1024*1024*1024*1024
+ stat = stat[:-1]
+ self.value[self.stats[idx]] = int (stat) * multiplier
+
+ def __str__(self):
+ '''Dump the MemoryMeasurement current value'''
+ s = ''
+ for key in self.value.keys():
+ if s:
+ s += "\n"
+ s += "%8s = %s" % (key, self.value[key])
+ return s
+
+
+class TesterTestCase(TestCase):
+ def __init__(self):
+ TestCase.__init__(self)
+ self.verbose = True
+ self.num_steps = 5
+
+ 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):
+ if self.num_steps > 0:
+ thread.StepOver()
+ self.num_steps = self.num_steps - 1
+ else:
+ thread.process.Kill()
+
+ 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))
+
+ if self.Launch():
+ while not self.done:
+ self.WaitForNextProcessEvent()
+ else:
+ print "error: failed to launch process"
+ 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:])
+ mem = MemoryMeasurement(os.getpid())
+ mem.Measure()
+ print str(mem)
+ lldb.SBDebugger.Terminate()
+ # print "sleeeping for 100 seconds"
+ # time.sleep(100)
diff --git a/examples/python/process_events.py b/examples/python/process_events.py
new file mode 100755
index 0000000000000..e8ccc5f902302
--- /dev/null
+++ b/examples/python/process_events.py
@@ -0,0 +1,278 @@
+#!/usr/bin/python
+
+#----------------------------------------------------------------------
+# Be sure to add the python path that points to the LLDB shared library.
+# On MacOSX csh, tcsh:
+# setenv PYTHONPATH /Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Resources/Python
+# On MacOSX sh, bash:
+# export PYTHONPATH=/Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Resources/Python
+#----------------------------------------------------------------------
+
+import commands
+import optparse
+import os
+import platform
+import sys
+
+#----------------------------------------------------------------------
+# Code that auto imports LLDB
+#----------------------------------------------------------------------
+try:
+ # Just try for LLDB in case PYTHONPATH is already correctly setup
+ import lldb
+except ImportError:
+ lldb_python_dirs = list()
+ # lldb is not in the PYTHONPATH, try some defaults for the current platform
+ platform_system = platform.system()
+ if platform_system == 'Darwin':
+ # 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')
+ 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:
+ import lldb
+ except ImportError:
+ pass
+ else:
+ print 'imported lldb from: "%s"' % (lldb_python_dir)
+ success = True
+ break
+ if not success:
+ 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 )
+ 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:
+
+#----------------------------------------------------------------------
+# 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)
+ 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)
+ 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)
+ 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)
+ 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)
+ 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)
+
+ 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
+ if launch_info and options.breakpoints:
+ for bp in options.breakpoints:
+ 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)
+ else:
+ if options.attach_pid != -1:
+ print 'Attaching to process %i...' % (options.attach_pid)
+ else:
+ if options.attach_wait:
+ 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)
+
+ # 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
+ process.Continue()
+
+ listener = debugger.GetListener()
+ # sign up for process state change events
+ stop_idx = 0
+ done = False
+ while not done:
+ event = lldb.SBEvent()
+ if listener.WaitForEvent (options.event_timeout, event):
+ if lldb.SBProcess.EventIsProcessEvent(event):
+ state = lldb.SBProcess.GetStateFromEvent (event)
+ if state == lldb.eStateInvalid:
+ # Not a state event
+ print 'process event = %s' % (event)
+ else:
+ print "process state changed event: %s" % (lldb.SBDebugger.StateAsCString(state))
+ if state == lldb.eStateStopped:
+ if stop_idx == 0:
+ if launch_info:
+ print "process %u launched" % (pid)
+ 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)
+ else:
+ if options.verbose:
+ print "process %u stopped" % (pid)
+ run_commands (command_interpreter, options.stop_commands)
+ stop_idx += 1
+ 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)
+ else:
+ 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)
+ 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
+ if options.verbose:
+ print "process %u resumed" % (pid)
+ elif state == lldb.eStateUnloaded:
+ print "process %u unloaded, this shouldn't happen" % (pid)
+ done = True
+ elif state == lldb.eStateConnected:
+ print "process connected"
+ elif state == lldb.eStateAttaching:
+ print "process attaching"
+ elif state == lldb.eStateLaunching:
+ print "process launching"
+ else:
+ print 'event = %s' % (event)
+ else:
+ # timeout waiting for an event
+ print "no process event for %u seconds, killing the process..." % (options.event_timeout)
+ done = True
+ # Now that we are done dump the stdout and stderr
+ process_stdout = process.GetSTDOUT(1024)
+ if process_stdout:
+ print "Process STDOUT:\n%s" % (process_stdout)
+ while process_stdout:
+ process_stdout = process.GetSTDOUT(1024)
+ print process_stdout
+ process_stderr = process.GetSTDERR(1024)
+ if process_stderr:
+ print "Process STDERR:\n%s" % (process_stderr)
+ while process_stderr:
+ process_stderr = process.GetSTDERR(1024)
+ print process_stderr
+ process.Kill() # kill the process
+ else:
+ if error:
+ print error
+ else:
+ if launch_info:
+ print 'error: launch failed'
+ else:
+ print 'error: attach failed'
+
+ lldb.SBDebugger.Terminate()
+
+if __name__ == '__main__':
+ main(sys.argv[1:]) \ No newline at end of file
diff --git a/examples/python/pytracer.py b/examples/python/pytracer.py
new file mode 100644
index 0000000000000..61bbceefe0577
--- /dev/null
+++ b/examples/python/pytracer.py
@@ -0,0 +1,328 @@
+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 getLineNumber(self):
+ return self.t.tb_lineno if self.t != None else None
+
+ def getNext(self):
+ return TracebackFancy(self.t.tb_next)
+
+ 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 getTraceback(self):
+ return TracebackFancy(self.etraceback)
+
+ def __nonzero__(self):
+ return self.etraceback != None or self.etype != None or self.evalue != None
+
+ def getType(self):
+ return str(self.etype)
+
+ 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 getFilename(self):
+ return self.c.co_filename if self.c != None else ""
+
+ def getVariables(self):
+ return self.c.co_varnames if self.c != None else []
+
+ def getName(self):
+ return self.c.co_name if self.c != 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 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 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 {}
+
+class FrameFancy:
+ def __init__(self,frame):
+ self.f = frame
+
+ def getCaller(self):
+ return FrameFancy(self.f.f_back)
+
+ def getLineNumber(self):
+ return self.f.f_lineno if self.f != None else 0
+
+ def getCodeInformation(self):
+ return CodeFancy(self.f.f_code) if self.f != None else None
+
+ def getExceptionInfo(self):
+ return ExceptionFancy(self.f) if self.f != None else None
+
+ def getName(self):
+ return self.getCodeInformation().getName() if self.f != None else ""
+
+ def getFileName(self):
+ return self.getCodeInformation().getFileName() if self.f != None else ""
+
+ 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 returnEvent(self,frame,retval):
+ pass
+
+ def exceptionEvent(self,frame,exception,value,traceback):
+ pass
+
+ def cCallEvent(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 enable(t=None):
+ global tracer_impl
+ if t:
+ tracer_impl = t
+ sys.settrace(the_tracer_entrypoint)
+
+def disable():
+ 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 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
+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 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 g(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)
+
+def total(initial=5, *numbers, **keywords):
+ count = initial
+ for number in numbers:
+ count += number
+ for key in keywords:
+ count += keywords[key]
+ 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()
diff --git a/examples/python/sbvalue.py b/examples/python/sbvalue.py
new file mode 100755
index 0000000000000..59c0b61e55283
--- /dev/null
+++ b/examples/python/sbvalue.py
@@ -0,0 +1,255 @@
+#!/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/examples/python/scripted_step.py b/examples/python/scripted_step.py
new file mode 100644
index 0000000000000..8affb9e83220d
--- /dev/null
+++ b/examples/python/scripted_step.py
@@ -0,0 +1,186 @@
+#############################################################################
+# This script contains two trivial examples of simple "scripted step" classes.
+# To fully understand how the lldb "Thread Plan" architecture works, read the
+# comments at the beginning of ThreadPlan.h in the lldb sources. The python
+# 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.
+# 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
+# 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,
+# and another continue would complete the first "step-over".
+#
+# lldb represents this system with a stack of "Thread Plans". Each time a new
+# stepping operation is requested, a new plan is pushed on the stack. When the
+# operation completes, it is pushed off the stack.
+#
+# The bottom-most plan in the stack is the immediate controller of stepping,
+# most importantly, when the process resumes, the bottom most plan will get
+# asked whether to set the program running freely, or to instruction-single-step
+# 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
+# "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
+# 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
+# breakpoint hit is propagated up the stack to the "base" thread plan, which
+# is the one that handles random breakpoint hits.
+#
+# 2) Then the plan that won the first round is asked if the process should stop.
+# This is done in the "should_stop" method. The scripted plans actually do
+# three jobs in should_stop:
+# a) They determine if they have completed their job or not. If they have
+# they indicate that by calling SetPlanComplete on their thread plan.
+# b) They decide whether they want to return control to the user or not.
+# They do this by returning True or False respectively.
+# c) If they are not done, they set up whatever machinery they will use
+# 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
+# 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
+# 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
+# stack was done, then it will be popped and the next plan will take control
+# and its "should_stop" will be called.
+#
+# Note also, there should be another method called when your plan is popped,
+# to allow you to do whatever cleanup is required. I haven't gotten to that
+# yet. For now you should do that at the same time you mark your plan complete.
+#
+# 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.
+#
+# That is better handled in the second example by using the built-in StepOverRange
+# thread plan.
+#
+# To use these stepping modes, you would do:
+#
+# (lldb) command script import scripted_step.py
+# (lldb) thread step-scripted -C scripted_step.SimpleStep
+# or
+#
+# (lldb) thread step-scripted -C scripted_step.StepWithPlan
+
+import lldb
+
+class SimpleStep:
+ 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):
+ # 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:
+ return True
+ else:
+ return False
+
+ 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):
+ return True
+
+class StepWithPlan:
+ 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);
+
+ 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):
+ if self.step_thread_plan.IsPlanComplete():
+ self.thread_plan.SetPlanComplete(True)
+ return True
+ else:
+ return False
+
+ 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):
+ self.thread_plan = thread_plan
+ self.start_frame = thread_plan.GetThread().GetFrameAtIndex(0)
+ self.queue_next_plan()
+
+ 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)
+
+ 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):
+ if not self.step_thread_plan.IsPlanComplete():
+ return False
+
+ frame = self.thread_plan.GetThread().GetFrameAtIndex(0)
+ if not self.start_frame.IsEqual(frame):
+ self.thread_plan.SetPlanComplete(True)
+ return True
+
+ # This part checks the condition. In this case we are expecting
+ # some integer variable called "a", and will stop when it is 20.
+ a_var = frame.FindVariable("a")
+
+ if not a_var.IsValid():
+ print "A was not valid."
+ return True
+
+ error = lldb.SBError()
+ a_value = a_var.GetValueAsSigned (error)
+ if not error.Success():
+ print "A value was not good."
+ return True
+
+ if a_value == 20:
+ self.thread_plan.SetPlanComplete(True)
+ return True
+ else:
+ self.queue_next_plan()
+ return False
+
+ def should_step (self):
+ return True
+
diff --git a/examples/python/sources.py b/examples/python/sources.py
new file mode 100644
index 0000000000000..0eb5858805bea
--- /dev/null
+++ b/examples/python/sources.py
@@ -0,0 +1,28 @@
+#!/usr/bin/python
+
+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.'''
+ module_names = shlex.split(command)
+ target = debugger.GetSelectedTarget()
+ if module_names:
+ for module_name in module_names:
+ dump_module_sources(target.module[module_name], result)
+ else:
+ for module in target.modules:
+ dump_module_sources(module, result)
+
+
+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')
+ print 'The "info_sources" command has been installed, type "help info_sources" or "info_sources --help" for detailed help.'
diff --git a/examples/python/stacks.py b/examples/python/stacks.py
new file mode 100755
index 0000000000000..06907e159d7fc
--- /dev/null
+++ b/examples/python/stacks.py
@@ -0,0 +1,59 @@
+#!/usr/bin/python
+
+import lldb
+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)
+ 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
+ print "thread %u" % (thread.id)
+ for frame in thread.frames:
+ if last_frame:
+ 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)
+ 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
+ print "<%#7x> %s" % (first_frame_size, last_frame)
+ if first_frame_size:
+ name = last_frame.name
+ if name not in frame_info:
+ frame_info[name] = first_frame_size
+ else:
+ frame_info[name] += first_frame_size
+ else:
+ # Second or higher frame
+ frame_size = frame.fp - last_frame.fp
+ print "<%#7x> %s" % (frame_size, frame)
+ if frame_size > 0:
+ name = frame.name
+ if name not in frame_info:
+ frame_info[name] = frame_size
+ else:
+ 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." \ No newline at end of file
diff --git a/examples/python/symbolication.py b/examples/python/symbolication.py
new file mode 100755
index 0000000000000..2f2a274dbc41d
--- /dev/null
+++ b/examples/python/symbolication.py
@@ -0,0 +1,640 @@
+#!/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, verbose = False):
+ if self.symbolication == None:
+ self.symbolication = ''
+ self.inlined = False
+ sym_ctx = self.get_symbol_context()
+ if sym_ctx:
+ module = sym_ctx.GetModule()
+ if module:
+ # Print full source file path in verbose mode
+ if verbose:
+ self.symbolication += str(module.GetFileSpec()) + '`'
+ else:
+ 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():
+ # Print full source file path in verbose mode
+ if verbose:
+ self.symbolication += ' at %s' % line_entry.GetFileSpec()
+ else:
+ 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
+
+ @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)
+ return obj
+ else:
+ return None
+
+ 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.resolved = False
+ self.unavailable = False
+ 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
+
+ @classmethod
+ def InitWithSBTargetAndSBModule(cls, target, module):
+ '''Initialize this Image object with a module from a target.'''
+ obj = cls(module.file.fullpath, module.uuid)
+ obj.resolved_path = module.platform_file.fullpath
+ obj.resolved = True
+ obj.arch = module.triple
+ for section in module.sections:
+ symb_section = Section.InitWithSBTargetAndSBSection(target, section)
+ if 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)
+
+ def debug_dump(self):
+ print 'path = "%s"' % (self.path)
+ print 'resolved_path = "%s"' % (self.resolved_path)
+ print 'resolved = %i' % (self.resolved)
+ print 'unavailable = %i' % (self.unavailable)
+ print 'uuid = %s' % (self.uuid)
+ print 'section_infos = %s' % (self.section_infos)
+ print 'identifier = "%s"' % (self.identifier)
+ print 'version = %s' % (self.version)
+ print 'arch = %s' % (self.arch)
+ 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:
+ s += "%s " % (self.get_uuid())
+ if self.arch:
+ s += "%s " % (self.arch)
+ if self.version:
+ s += "%s " % (self.version)
+ resolved_path = self.get_resolved_path()
+ if resolved_path:
+ s += "%s " % (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):
+ if self.unavailable:
+ return None # We already warned that we couldn't find this module, so don't return an error string
+ # Load this module into "target" using the section infos to
+ # 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:
+ # 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)
+ if not self.module:
+ 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)
+ if not self.module:
+ 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
+ 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
+ self.resolved = True
+ return True
+
+ def get_uuid(self):
+ if not self.uuid and self.module:
+ self.uuid = uuid.UUID(self.module.GetUUIDString())
+ return self.uuid
+
+ def get_normalized_uuid_string(self):
+ if self.uuid:
+ return str(self.uuid).upper()
+ return None
+
+ def create_target(self):
+ '''Create a target using the information in this Image object.'''
+ if self.unavailable:
+ return None
+
+ 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
+ self.addr_mask = 0xffffffffffffffff
+
+ @classmethod
+ def InitWithSBTarget(cls, target):
+ obj = cls()
+ obj.target = target
+ obj.images = list();
+ triple = target.triple
+ if triple:
+ arch = triple.split('-')[0]
+ if "arm" in arch:
+ obj.addr_mask = 0xfffffffffffffffe
+
+ for module in target.modules:
+ image = Image.InitWithSBTargetAndSBModule(target, module)
+ obj.images.append(image)
+ return obj
+
+ 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:
+ s += str(m) + "\n"
+ 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)
+ if len(images) == 0:
+ regex_text = '^.*\.%s$' % (identifier)
+ regex = re.compile(regex_text)
+ for image in self.images:
+ 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):
+ 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:
+ if self.target.GetAddressByteSize() == 4:
+ triple = self.target.triple
+ if triple:
+ arch = triple.split('-')[0]
+ if "arm" in arch:
+ self.addr_mask = 0xfffffffffffffffe
+ return self.target
+ return None
+
+
+ def symbolicate(self, load_addr, verbose = False):
+ if not self.target:
+ self.create_target()
+ if self.target:
+ live_process = False
+ process = self.target.process
+ if process:
+ state = process.state
+ if state > lldb.eStateUnloaded and state < lldb.eStateDetached:
+ live_process = True
+ # If we don't have a live process, we can attempt to find the image
+ # 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)
+ if image:
+ image.add_module (self.target)
+ symbolicated_address = Address(self.target, load_addr)
+ 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:
+ 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 (verbose)
+
+ # push the new frame onto the new frame stack
+ 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):
+ 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 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();
+ 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, 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:])
diff --git a/examples/python/types.py b/examples/python/types.py
new file mode 100755
index 0000000000000..60ea7514c13a7
--- /dev/null
+++ b/examples/python/types.py
@@ -0,0 +1,265 @@
+#!/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
+#----------------------------------------------------------------------
+
+import commands
+import platform
+import os
+import re
+import signal
+import sys
+
+try:
+ # Just try for LLDB in case PYTHONPATH is already correctly setup
+ import lldb
+except ImportError:
+ lldb_python_dirs = list()
+ # lldb is not in the PYTHONPATH, try some defaults for the current platform
+ platform_system = platform.system()
+ if platform_system == 'Darwin':
+ # 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')
+ 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:
+ import lldb
+ except ImportError:
+ pass
+ else:
+ print 'imported lldb from: "%s"' % (lldb_python_dir)
+ success = True
+ break
+ if not success:
+ print "error: couldn't locate the 'lldb' module, please set PYTHONPATH correctly"
+ sys.exit(1)
+
+import commands
+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)
+
+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
+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
+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
+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 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)
+ 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=[])
+ return parser
+
+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)
+ byte_size = type.GetByteSize()
+ # if end_offset < byte_size:
+ # last_member_padding = byte_size - end_offset
+ # print '%+4u <%u> padding' % (end_offset, last_member_padding)
+ # padding += last_member_padding
+ print 'Total byte size: %u' % (byte_size)
+ print 'Total pad bytes: %u' % (padding)
+ if padding > 0:
+ 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):
+ prev_end_offset = base_offset
+ typename = type.GetName()
+ byte_size = type.GetByteSize()
+ if member_name and member_name != typename:
+ 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)
+ if match:
+ return (base_offset + byte_size, padding)
+
+ members = type.members
+ if members:
+ for member_idx, member in enumerate(members):
+ member_type = member.GetType()
+ member_canonical_type = member_type.GetCanonicalType()
+ member_type_class = member_canonical_type.GetTypeClass()
+ member_name = member.GetName()
+ member_offset = member.GetOffsetInBytes()
+ member_total_offset = member_offset + base_offset
+ member_byte_size = member_type.GetByteSize()
+ 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():
+ ptr_size = target.GetAddressByteSize()
+ print '%+4u <%3u> %s__vtbl_ptr_type * _vptr;' % (prev_end_offset, ptr_size, ' ' * (depth + 1))
+ prev_end_offset = ptr_size
+ else:
+ if prev_end_offset < member_total_offset:
+ 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)
+ else:
+ prev_end_offset = member_total_offset + member_byte_size
+ member_typename = member_type.GetName()
+ if member.IsBitfield():
+ 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))
+ padding += last_member_padding
+ else:
+ if 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
+ 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
+ # shell would
+ command_args = shlex.split(command)
+ parser = create_types_options(True)
+ 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.SetStatus (lldb.eReturnStatusFailed)
+ return "option parsing failed" # returning a string is the same as returning an error whose description is the string
+ verify_types(debugger.GetSelectedTarget(), options)
+
+@lldb.command("parse_all_struct_class_types")
+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)
+ 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):
+
+ if not target:
+ print 'error: invalid target'
+ return
+
+ modules = list()
+ if len(options.modules) == 0:
+ # Append just the main executable if nothing was specified
+ module = target.modules[0]
+ if module:
+ modules.append(module)
+ else:
+ for module_name in options.modules:
+ module = lldb.target.module[module_name]
+ if module:
+ modules.append(module)
+
+ if modules:
+ for module in modules:
+ print 'module: %s' % (module.file)
+ if options.typenames:
+ for typename in options.typenames:
+ types = module.FindTypes(typename)
+ 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)
+ else:
+ print 'error: no type matches "%s" in "%s"' % (typename, module.file)
+ else:
+ 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)
+ 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"
+ # 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
+ error = lldb.SBError()
+ target = debugger.CreateTarget (path,
+ options.arch,
+ options.platform,
+ True,
+ error)
+ if error.Fail():
+ print error.GetCString()
+ continue
+ 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' \ No newline at end of file
diff --git a/examples/python/x86_64_linux_target_definition.py b/examples/python/x86_64_linux_target_definition.py
new file mode 100644
index 0000000000000..06cbe4c829635
--- /dev/null
+++ b/examples/python/x86_64_linux_target_definition.py
@@ -0,0 +1,353 @@
+#!/usr/bin/python
+#===-- x86_64_linux_target_definition.py -----------------------------*- C++ -*-===//
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===----------------------------------------------------------------------===//
+
+#----------------------------------------------------------------------
+# DESCRIPTION
+#
+# This file can be used with the following setting:
+# plugin.process.gdb-remote.target-definition-file
+# This setting should be used when you are trying to connect to a
+# remote GDB server that doesn't support any of the register discovery
+# packets that LLDB normally uses.
+#
+# Why is this necessary? LLDB doesn't require a new build of LLDB that
+# targets each new architecture you will debug with. Instead, all
+# architectures are supported and LLDB relies on extra GDB server
+# packets to discover the target we are connecting to so that is can
+# show the right registers for each target. This allows the GDB server
+# to change and add new registers without requiring a new LLDB build
+# just so we can see new registers.
+#
+# This file implements the x86_64 registers for the darwin version of
+# GDB and allows you to connect to servers that use this register set.
+#
+# USAGE
+#
+# (lldb) settings set plugin.process.gdb-remote.target-definition-file /path/to/x86_64_linux_target_definition.py
+# (lldb) gdb-remote other.baz.com:1234
+#
+# The target definition file will get used if and only if the
+# qRegisterInfo packets are not supported when connecting to a remote
+# GDB server.
+#----------------------------------------------------------------------
+from lldb import *
+
+# Compiler and DWARF register numbers
+name_to_gcc_dwarf_regnum = {
+ 'rax' : 0 ,
+ 'rdx' : 1 ,
+ 'rcx' : 2 ,
+ 'rbx' : 3 ,
+ 'rsi' : 4 ,
+ 'rdi' : 5 ,
+ 'rbp' : 6 ,
+ 'rsp' : 7 ,
+ 'r8' : 8 ,
+ 'r9' : 9 ,
+ 'r10' : 10,
+ 'r11' : 11,
+ 'r12' : 12,
+ 'r13' : 13,
+ 'r14' : 14,
+ 'r15' : 15,
+ 'rip' : 16,
+ 'xmm0' : 17,
+ 'xmm1' : 18,
+ 'xmm2' : 19,
+ 'xmm3' : 20,
+ 'xmm4' : 21,
+ 'xmm5' : 22,
+ 'xmm6' : 23,
+ 'xmm7' : 24,
+ 'xmm8' : 25,
+ 'xmm9' : 26,
+ 'xmm10' : 27,
+ 'xmm11' : 28,
+ 'xmm12' : 29,
+ 'xmm13' : 30,
+ 'xmm14' : 31,
+ 'xmm15' : 32,
+ 'stmm0' : 33,
+ 'stmm1' : 34,
+ 'stmm2' : 35,
+ 'stmm3' : 36,
+ 'stmm4' : 37,
+ 'stmm5' : 38,
+ 'stmm6' : 39,
+ 'stmm7' : 30,
+ 'ymm0' : 41,
+ 'ymm1' : 42,
+ 'ymm2' : 43,
+ 'ymm3' : 44,
+ 'ymm4' : 45,
+ 'ymm5' : 46,
+ 'ymm6' : 47,
+ 'ymm7' : 48,
+ 'ymm8' : 49,
+ 'ymm9' : 40,
+ 'ymm10' : 41,
+ 'ymm11' : 42,
+ 'ymm12' : 43,
+ 'ymm13' : 44,
+ 'ymm14' : 45,
+ 'ymm15' : 46
+};
+
+name_to_gdb_regnum = {
+ 'rax' : 0,
+ 'rbx' : 1,
+ 'rcx' : 2,
+ 'rdx' : 3,
+ 'rsi' : 4,
+ 'rdi' : 5,
+ 'rbp' : 6,
+ 'rsp' : 7,
+ 'r8' : 8,
+ 'r9' : 9,
+ 'r10' : 10,
+ 'r11' : 11,
+ 'r12' : 12,
+ 'r13' : 13,
+ 'r14' : 14,
+ 'r15' : 15,
+ 'rip' : 16,
+ 'rflags': 17,
+ 'cs' : 18,
+ 'ss' : 19,
+ 'ds' : 20,
+ 'es' : 21,
+ 'fs' : 22,
+ 'gs' : 23,
+ 'stmm0' : 24,
+ 'stmm1' : 25,
+ 'stmm2' : 26,
+ 'stmm3' : 27,
+ 'stmm4' : 28,
+ 'stmm5' : 29,
+ 'stmm6' : 30,
+ 'stmm7' : 31,
+ 'fctrl' : 32,
+ 'fstat' : 33,
+ 'ftag' : 34,
+ 'fiseg' : 35,
+ 'fioff' : 36,
+ 'foseg' : 37,
+ 'fooff' : 38,
+ 'fop' : 39,
+ 'xmm0' : 40,
+ 'xmm1' : 41,
+ 'xmm2' : 42,
+ 'xmm3' : 43,
+ 'xmm4' : 44,
+ 'xmm5' : 45,
+ 'xmm6' : 46,
+ 'xmm7' : 47,
+ 'xmm8' : 48,
+ 'xmm9' : 49,
+ 'xmm10' : 50,
+ 'xmm11' : 51,
+ 'xmm12' : 52,
+ 'xmm13' : 53,
+ 'xmm14' : 54,
+ 'xmm15' : 55,
+ 'mxcsr' : 56,
+ 'ymm0' : 57,
+ 'ymm1' : 58,
+ 'ymm2' : 59,
+ 'ymm3' : 60,
+ 'ymm4' : 61,
+ 'ymm5' : 62,
+ 'ymm6' : 63,
+ 'ymm7' : 64,
+ 'ymm8' : 65,
+ 'ymm9' : 66,
+ 'ymm10' : 67,
+ 'ymm11' : 68,
+ 'ymm12' : 69,
+ 'ymm13' : 70,
+ 'ymm14' : 71,
+ 'ymm15' : 72
+};
+
+name_to_generic_regnum = {
+ 'rip' : LLDB_REGNUM_GENERIC_PC,
+ 'rsp' : LLDB_REGNUM_GENERIC_SP,
+ 'rbp' : LLDB_REGNUM_GENERIC_FP,
+ 'rdi' : LLDB_REGNUM_GENERIC_ARG1,
+ 'rsi' : LLDB_REGNUM_GENERIC_ARG2,
+ 'rdx' : LLDB_REGNUM_GENERIC_ARG3,
+ 'rcx' : LLDB_REGNUM_GENERIC_ARG4,
+ 'r8' : LLDB_REGNUM_GENERIC_ARG5,
+ 'r9' : LLDB_REGNUM_GENERIC_ARG6
+};
+
+def get_reg_num (reg_num_dict, reg_name):
+ if reg_name in reg_num_dict:
+ return reg_num_dict[reg_name]
+ return LLDB_INVALID_REGNUM
+
+x86_64_register_infos = [
+{ 'name':'rax' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo },
+{ 'name':'rbx' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo },
+{ 'name':'rcx' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo, 'alt-name':'arg4' },
+{ 'name':'rdx' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo, 'alt-name':'arg3' },
+{ 'name':'rsi' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo, 'alt-name':'arg2' },
+{ 'name':'rdi' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo, 'alt-name':'arg1' },
+{ 'name':'rbp' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo, 'alt-name':'fp' },
+{ 'name':'rsp' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo, 'alt-name':'sp' },
+{ 'name':'r8' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo, 'alt-name':'arg5' },
+{ 'name':'r9' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo, 'alt-name':'arg6' },
+{ 'name':'r10' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo },
+{ 'name':'r11' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo },
+{ 'name':'r12' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo },
+{ 'name':'r13' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo },
+{ 'name':'r14' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo },
+{ 'name':'r15' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo },
+{ 'name':'rip' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo, 'alt-name':'pc' },
+{ 'name':'rflags', 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
+{ 'name':'cs' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
+{ 'name':'ss' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
+{ 'name':'ds' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
+{ 'name':'es' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
+{ 'name':'fs' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
+{ 'name':'gs' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
+{ 'name':'stmm0' , 'set':1, 'bitsize':80 , 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'stmm1' , 'set':1, 'bitsize':80 , 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'stmm2' , 'set':1, 'bitsize':80 , 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'stmm3' , 'set':1, 'bitsize':80 , 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'stmm4' , 'set':1, 'bitsize':80 , 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'stmm5' , 'set':1, 'bitsize':80 , 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'stmm6' , 'set':1, 'bitsize':80 , 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'stmm7' , 'set':1, 'bitsize':80 , 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'fctrl' , 'set':1, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
+{ 'name':'fstat' , 'set':1, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
+{ 'name':'ftag' , 'set':1, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
+{ 'name':'fiseg' , 'set':1, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
+{ 'name':'fioff' , 'set':1, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
+{ 'name':'foseg' , 'set':1, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
+{ 'name':'fooff' , 'set':1, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
+{ 'name':'fop' , 'set':1, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
+{ 'name':'xmm0' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'xmm1' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'xmm2' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'xmm3' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'xmm4' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'xmm5' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'xmm6' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'xmm7' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'xmm8' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'xmm9' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'xmm10' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'xmm11' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'xmm12' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'xmm13' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'xmm14' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'xmm15' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'mxcsr' , 'set':1, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
+{ 'name':'orig_rax' , 'set':1, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatHex },
+# Registers that are contained in or composed of one of more other registers
+{ 'name':'eax' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rax[31:0]' },
+{ 'name':'ebx' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rbx[31:0]' },
+{ 'name':'ecx' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rcx[31:0]' },
+{ 'name':'edx' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rdx[31:0]' },
+{ 'name':'edi' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rdi[31:0]' },
+{ 'name':'esi' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rsi[31:0]' },
+{ 'name':'ebp' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rbp[31:0]' },
+{ 'name':'esp' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rsp[31:0]' },
+{ 'name':'r8d' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r8[31:0]' },
+{ 'name':'r9d' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r9[31:0]' },
+{ 'name':'r10d' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r10[31:0]' },
+{ 'name':'r11d' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r11[31:0]' },
+{ 'name':'r12d' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r12[31:0]' },
+{ 'name':'r13d' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r13[31:0]' },
+{ 'name':'r14d' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r14[31:0]' },
+{ 'name':'r15d' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r15[31:0]' },
+
+{ 'name':'ax' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rax[15:0]' },
+{ 'name':'bx' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rbx[15:0]' },
+{ 'name':'cx' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rcx[15:0]' },
+{ 'name':'dx' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rdx[15:0]' },
+{ 'name':'di' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rdi[15:0]' },
+{ 'name':'si' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rsi[15:0]' },
+{ 'name':'bp' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rbp[15:0]' },
+{ 'name':'sp' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rsp[15:0]' },
+{ 'name':'r8w' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r8[15:0]' },
+{ 'name':'r9w' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r9[15:0]' },
+{ 'name':'r10w' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r10[15:0]' },
+{ 'name':'r11w' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r11[15:0]' },
+{ 'name':'r12w' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r12[15:0]' },
+{ 'name':'r13w' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r13[15:0]' },
+{ 'name':'r14w' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r14[15:0]' },
+{ 'name':'r15w' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r15[15:0]' },
+
+{ 'name':'ah' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rax[15:8]' },
+{ 'name':'bh' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rbx[15:8]' },
+{ 'name':'ch' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rcx[15:8]' },
+{ 'name':'dh' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rdx[15:8]' },
+
+{ 'name':'al' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rax[7:0]' },
+{ 'name':'bl' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rbx[7:0]' },
+{ 'name':'cl' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rcx[7:0]' },
+{ 'name':'dl' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rdx[7:0]' },
+{ 'name':'dil' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rdi[7:0]' },
+{ 'name':'sil' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rsi[7:0]' },
+{ 'name':'bpl' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rbp[7:0]' },
+{ 'name':'spl' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rsp[7:0]' },
+{ 'name':'r8l' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r8[7:0]' },
+{ 'name':'r9l' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r9[7:0]' },
+{ 'name':'r10l' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r10[7:0]' },
+{ 'name':'r11l' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r11[7:0]' },
+{ 'name':'r12l' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r12[7:0]' },
+{ 'name':'r13l' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r13[7:0]' },
+{ 'name':'r14l' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r14[7:0]' },
+{ 'name':'r15l' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r15[7:0]' },
+];
+
+g_target_definition = None
+
+def get_target_definition ():
+ global g_target_definition
+ if g_target_definition == None:
+ g_target_definition = {}
+ offset = 0
+ for reg_info in x86_64_register_infos:
+ reg_name = reg_info['name']
+
+ # Only fill in the offset if there is no 'slice' in the register info
+ if 'slice' not in reg_info and 'composite' not in reg_info:
+ reg_info['offset'] = offset
+ offset += reg_info['bitsize']/8
+
+ # Set the GCC/DWARF register number for this register if it has one
+ reg_num = get_reg_num(name_to_gcc_dwarf_regnum, reg_name)
+ if reg_num != LLDB_INVALID_REGNUM:
+ reg_info['gcc'] = reg_num
+ reg_info['dwarf'] = reg_num
+
+ # Set the generic register number for this register if it has one
+ reg_num = get_reg_num(name_to_generic_regnum, reg_name)
+ if reg_num != LLDB_INVALID_REGNUM:
+ reg_info['generic'] = reg_num
+
+ # Set the GDB register number for this register if it has one
+ reg_num = get_reg_num(name_to_gdb_regnum, reg_name)
+ if reg_num != LLDB_INVALID_REGNUM:
+ reg_info['gdb'] = reg_num
+
+ g_target_definition['sets'] = ['General Purpose Registers', 'Floating Point Registers']
+ g_target_definition['registers'] = x86_64_register_infos
+ g_target_definition['host-info'] = { 'triple' : 'x86_64-*-linux', 'endian': eByteOrderLittle }
+ g_target_definition['g-packet-size'] = offset
+ g_target_definition['breakpoint-pc-offset'] = -1
+ return g_target_definition
+
+def get_dynamic_setting(target, setting_name):
+ if setting_name == 'gdb-server-target-definition':
+ return get_target_definition() \ No newline at end of file
diff --git a/examples/python/x86_64_qemu_target_definition.py b/examples/python/x86_64_qemu_target_definition.py
new file mode 100644
index 0000000000000..7b246896d8bfa
--- /dev/null
+++ b/examples/python/x86_64_qemu_target_definition.py
@@ -0,0 +1,352 @@
+#!/usr/bin/python
+#===-- x86_64_qemu_target_definition.py -----------------------------*- C++ -*-===//
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===----------------------------------------------------------------------===//
+
+#----------------------------------------------------------------------
+# DESCRIPTION
+#
+# This file can be used with the following setting:
+# plugin.process.gdb-remote.target-definition-file
+# This setting should be used when you are trying to connect to a
+# remote GDB server that doesn't support any of the register discovery
+# packets that LLDB normally uses.
+#
+# Why is this necessary? LLDB doesn't require a new build of LLDB that
+# targets each new architecture you will debug with. Instead, all
+# architectures are supported and LLDB relies on extra GDB server
+# packets to discover the target we are connecting to so that is can
+# show the right registers for each target. This allows the remote stub
+# to change and add new registers without requiring a new LLDB build
+# just so we can see new registers.
+#
+# This file implements the x86_64 registers for the user mode qemu on linux.
+# The only difference with the Linux file is the absense of orig_rax register.
+#
+# USAGE
+#
+# (lldb) settings set plugin.process.gdb-remote.target-definition-file /path/to/x86_64_qemu_target_definition.py
+# (lldb) gdb-remote other.baz.com:1234
+#
+# The target definition file will get used if and only if the
+# qRegisterInfo packets are not supported when connecting to a remote
+# GDB stub.
+#----------------------------------------------------------------------
+from lldb import *
+
+# Compiler and DWARF register numbers
+name_to_gcc_dwarf_regnum = {
+ 'rax' : 0 ,
+ 'rdx' : 1 ,
+ 'rcx' : 2 ,
+ 'rbx' : 3 ,
+ 'rsi' : 4 ,
+ 'rdi' : 5 ,
+ 'rbp' : 6 ,
+ 'rsp' : 7 ,
+ 'r8' : 8 ,
+ 'r9' : 9 ,
+ 'r10' : 10,
+ 'r11' : 11,
+ 'r12' : 12,
+ 'r13' : 13,
+ 'r14' : 14,
+ 'r15' : 15,
+ 'rip' : 16,
+ 'xmm0' : 17,
+ 'xmm1' : 18,
+ 'xmm2' : 19,
+ 'xmm3' : 20,
+ 'xmm4' : 21,
+ 'xmm5' : 22,
+ 'xmm6' : 23,
+ 'xmm7' : 24,
+ 'xmm8' : 25,
+ 'xmm9' : 26,
+ 'xmm10' : 27,
+ 'xmm11' : 28,
+ 'xmm12' : 29,
+ 'xmm13' : 30,
+ 'xmm14' : 31,
+ 'xmm15' : 32,
+ 'stmm0' : 33,
+ 'stmm1' : 34,
+ 'stmm2' : 35,
+ 'stmm3' : 36,
+ 'stmm4' : 37,
+ 'stmm5' : 38,
+ 'stmm6' : 39,
+ 'stmm7' : 30,
+ 'ymm0' : 41,
+ 'ymm1' : 42,
+ 'ymm2' : 43,
+ 'ymm3' : 44,
+ 'ymm4' : 45,
+ 'ymm5' : 46,
+ 'ymm6' : 47,
+ 'ymm7' : 48,
+ 'ymm8' : 49,
+ 'ymm9' : 40,
+ 'ymm10' : 41,
+ 'ymm11' : 42,
+ 'ymm12' : 43,
+ 'ymm13' : 44,
+ 'ymm14' : 45,
+ 'ymm15' : 46
+};
+
+name_to_gdb_regnum = {
+ 'rax' : 0,
+ 'rbx' : 1,
+ 'rcx' : 2,
+ 'rdx' : 3,
+ 'rsi' : 4,
+ 'rdi' : 5,
+ 'rbp' : 6,
+ 'rsp' : 7,
+ 'r8' : 8,
+ 'r9' : 9,
+ 'r10' : 10,
+ 'r11' : 11,
+ 'r12' : 12,
+ 'r13' : 13,
+ 'r14' : 14,
+ 'r15' : 15,
+ 'rip' : 16,
+ 'rflags': 17,
+ 'cs' : 18,
+ 'ss' : 19,
+ 'ds' : 20,
+ 'es' : 21,
+ 'fs' : 22,
+ 'gs' : 23,
+ 'stmm0' : 24,
+ 'stmm1' : 25,
+ 'stmm2' : 26,
+ 'stmm3' : 27,
+ 'stmm4' : 28,
+ 'stmm5' : 29,
+ 'stmm6' : 30,
+ 'stmm7' : 31,
+ 'fctrl' : 32,
+ 'fstat' : 33,
+ 'ftag' : 34,
+ 'fiseg' : 35,
+ 'fioff' : 36,
+ 'foseg' : 37,
+ 'fooff' : 38,
+ 'fop' : 39,
+ 'xmm0' : 40,
+ 'xmm1' : 41,
+ 'xmm2' : 42,
+ 'xmm3' : 43,
+ 'xmm4' : 44,
+ 'xmm5' : 45,
+ 'xmm6' : 46,
+ 'xmm7' : 47,
+ 'xmm8' : 48,
+ 'xmm9' : 49,
+ 'xmm10' : 50,
+ 'xmm11' : 51,
+ 'xmm12' : 52,
+ 'xmm13' : 53,
+ 'xmm14' : 54,
+ 'xmm15' : 55,
+ 'mxcsr' : 56,
+ 'ymm0' : 57,
+ 'ymm1' : 58,
+ 'ymm2' : 59,
+ 'ymm3' : 60,
+ 'ymm4' : 61,
+ 'ymm5' : 62,
+ 'ymm6' : 63,
+ 'ymm7' : 64,
+ 'ymm8' : 65,
+ 'ymm9' : 66,
+ 'ymm10' : 67,
+ 'ymm11' : 68,
+ 'ymm12' : 69,
+ 'ymm13' : 70,
+ 'ymm14' : 71,
+ 'ymm15' : 72
+};
+
+name_to_generic_regnum = {
+ 'rip' : LLDB_REGNUM_GENERIC_PC,
+ 'rsp' : LLDB_REGNUM_GENERIC_SP,
+ 'rbp' : LLDB_REGNUM_GENERIC_FP,
+ 'rdi' : LLDB_REGNUM_GENERIC_ARG1,
+ 'rsi' : LLDB_REGNUM_GENERIC_ARG2,
+ 'rdx' : LLDB_REGNUM_GENERIC_ARG3,
+ 'rcx' : LLDB_REGNUM_GENERIC_ARG4,
+ 'r8' : LLDB_REGNUM_GENERIC_ARG5,
+ 'r9' : LLDB_REGNUM_GENERIC_ARG6
+};
+
+def get_reg_num (reg_num_dict, reg_name):
+ if reg_name in reg_num_dict:
+ return reg_num_dict[reg_name]
+ return LLDB_INVALID_REGNUM
+
+x86_64_register_infos = [
+{ 'name':'rax' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo },
+{ 'name':'rbx' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo },
+{ 'name':'rcx' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo, 'alt-name':'arg4' },
+{ 'name':'rdx' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo, 'alt-name':'arg3' },
+{ 'name':'rsi' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo, 'alt-name':'arg2' },
+{ 'name':'rdi' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo, 'alt-name':'arg1' },
+{ 'name':'rbp' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo, 'alt-name':'fp' },
+{ 'name':'rsp' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo, 'alt-name':'sp' },
+{ 'name':'r8' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo, 'alt-name':'arg5' },
+{ 'name':'r9' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo, 'alt-name':'arg6' },
+{ 'name':'r10' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo },
+{ 'name':'r11' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo },
+{ 'name':'r12' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo },
+{ 'name':'r13' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo },
+{ 'name':'r14' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo },
+{ 'name':'r15' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo },
+{ 'name':'rip' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo, 'alt-name':'pc' },
+{ 'name':'rflags', 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
+{ 'name':'cs' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
+{ 'name':'ss' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
+{ 'name':'ds' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
+{ 'name':'es' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
+{ 'name':'fs' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
+{ 'name':'gs' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
+{ 'name':'stmm0' , 'set':1, 'bitsize':80 , 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'stmm1' , 'set':1, 'bitsize':80 , 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'stmm2' , 'set':1, 'bitsize':80 , 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'stmm3' , 'set':1, 'bitsize':80 , 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'stmm4' , 'set':1, 'bitsize':80 , 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'stmm5' , 'set':1, 'bitsize':80 , 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'stmm6' , 'set':1, 'bitsize':80 , 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'stmm7' , 'set':1, 'bitsize':80 , 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'fctrl' , 'set':1, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
+{ 'name':'fstat' , 'set':1, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
+{ 'name':'ftag' , 'set':1, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
+{ 'name':'fiseg' , 'set':1, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
+{ 'name':'fioff' , 'set':1, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
+{ 'name':'foseg' , 'set':1, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
+{ 'name':'fooff' , 'set':1, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
+{ 'name':'fop' , 'set':1, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
+{ 'name':'xmm0' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'xmm1' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'xmm2' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'xmm3' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'xmm4' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'xmm5' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'xmm6' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'xmm7' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'xmm8' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'xmm9' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'xmm10' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'xmm11' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'xmm12' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'xmm13' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'xmm14' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'xmm15' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'mxcsr' , 'set':1, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
+# Registers that are contained in or composed of one of more other registers
+{ 'name':'eax' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rax[31:0]' },
+{ 'name':'ebx' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rbx[31:0]' },
+{ 'name':'ecx' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rcx[31:0]' },
+{ 'name':'edx' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rdx[31:0]' },
+{ 'name':'edi' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rdi[31:0]' },
+{ 'name':'esi' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rsi[31:0]' },
+{ 'name':'ebp' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rbp[31:0]' },
+{ 'name':'esp' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rsp[31:0]' },
+{ 'name':'r8d' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r8[31:0]' },
+{ 'name':'r9d' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r9[31:0]' },
+{ 'name':'r10d' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r10[31:0]' },
+{ 'name':'r11d' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r11[31:0]' },
+{ 'name':'r12d' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r12[31:0]' },
+{ 'name':'r13d' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r13[31:0]' },
+{ 'name':'r14d' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r14[31:0]' },
+{ 'name':'r15d' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r15[31:0]' },
+
+{ 'name':'ax' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rax[15:0]' },
+{ 'name':'bx' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rbx[15:0]' },
+{ 'name':'cx' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rcx[15:0]' },
+{ 'name':'dx' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rdx[15:0]' },
+{ 'name':'di' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rdi[15:0]' },
+{ 'name':'si' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rsi[15:0]' },
+{ 'name':'bp' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rbp[15:0]' },
+{ 'name':'sp' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rsp[15:0]' },
+{ 'name':'r8w' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r8[15:0]' },
+{ 'name':'r9w' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r9[15:0]' },
+{ 'name':'r10w' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r10[15:0]' },
+{ 'name':'r11w' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r11[15:0]' },
+{ 'name':'r12w' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r12[15:0]' },
+{ 'name':'r13w' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r13[15:0]' },
+{ 'name':'r14w' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r14[15:0]' },
+{ 'name':'r15w' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r15[15:0]' },
+
+{ 'name':'ah' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rax[15:8]' },
+{ 'name':'bh' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rbx[15:8]' },
+{ 'name':'ch' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rcx[15:8]' },
+{ 'name':'dh' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rdx[15:8]' },
+
+{ 'name':'al' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rax[7:0]' },
+{ 'name':'bl' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rbx[7:0]' },
+{ 'name':'cl' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rcx[7:0]' },
+{ 'name':'dl' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rdx[7:0]' },
+{ 'name':'dil' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rdi[7:0]' },
+{ 'name':'sil' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rsi[7:0]' },
+{ 'name':'bpl' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rbp[7:0]' },
+{ 'name':'spl' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rsp[7:0]' },
+{ 'name':'r8l' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r8[7:0]' },
+{ 'name':'r9l' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r9[7:0]' },
+{ 'name':'r10l' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r10[7:0]' },
+{ 'name':'r11l' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r11[7:0]' },
+{ 'name':'r12l' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r12[7:0]' },
+{ 'name':'r13l' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r13[7:0]' },
+{ 'name':'r14l' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r14[7:0]' },
+{ 'name':'r15l' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r15[7:0]' },
+];
+
+g_target_definition = None
+
+def get_target_definition ():
+ global g_target_definition
+ if g_target_definition == None:
+ g_target_definition = {}
+ offset = 0
+ for reg_info in x86_64_register_infos:
+ reg_name = reg_info['name']
+
+ # Only fill in the offset if there is no 'slice' in the register info
+ if 'slice' not in reg_info and 'composite' not in reg_info:
+ reg_info['offset'] = offset
+ offset += reg_info['bitsize']/8
+
+ # Set the GCC/DWARF register number for this register if it has one
+ reg_num = get_reg_num(name_to_gcc_dwarf_regnum, reg_name)
+ if reg_num != LLDB_INVALID_REGNUM:
+ reg_info['gcc'] = reg_num
+ reg_info['dwarf'] = reg_num
+
+ # Set the generic register number for this register if it has one
+ reg_num = get_reg_num(name_to_generic_regnum, reg_name)
+ if reg_num != LLDB_INVALID_REGNUM:
+ reg_info['generic'] = reg_num
+
+ # Set the GDB register number for this register if it has one
+ reg_num = get_reg_num(name_to_gdb_regnum, reg_name)
+ if reg_num != LLDB_INVALID_REGNUM:
+ reg_info['gdb'] = reg_num
+
+ g_target_definition['sets'] = ['General Purpose Registers', 'Floating Point Registers']
+ g_target_definition['registers'] = x86_64_register_infos
+ g_target_definition['host-info'] = { 'triple' : 'x86_64-*-linux', 'endian': eByteOrderLittle }
+ g_target_definition['g-packet-size'] = offset
+ g_target_definition['breakpoint-pc-offset'] = -1
+ return g_target_definition
+
+def get_dynamic_setting(target, setting_name):
+ if setting_name == 'gdb-server-target-definition':
+ return get_target_definition()
diff --git a/examples/python/x86_64_target_definition.py b/examples/python/x86_64_target_definition.py
new file mode 100644
index 0000000000000..3a1290b62f809
--- /dev/null
+++ b/examples/python/x86_64_target_definition.py
@@ -0,0 +1,357 @@
+#!/usr/bin/python
+#===-- x86_64_target_definition.py -----------------------------*- C++ -*-===//
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===----------------------------------------------------------------------===//
+
+#----------------------------------------------------------------------
+# DESCRIPTION
+#
+# This file can be used with the following setting:
+# plugin.process.gdb-remote.target-definition-file
+# This setting should be used when you are trying to connect to a
+# remote GDB server that doesn't support any of the register discovery
+# packets that LLDB normally uses.
+#
+# Why is this necessary? LLDB doesn't require a new build of LLDB that
+# targets each new architecture you will debug with. Instead, all
+# architectures are supported and LLDB relies on extra GDB server
+# packets to discover the target we are connecting to so that is can
+# show the right registers for each target. This allows the GDB server
+# to change and add new registers without requiring a new LLDB build
+# just so we can see new registers.
+#
+# This file implements the x86_64 registers for the darwin version of
+# GDB and allows you to connect to servers that use this register set.
+#
+# USAGE
+#
+# (lldb) settings set plugin.process.gdb-remote.target-definition-file /path/to/x86_64_target_definition.py
+# (lldb) gdb-remote other.baz.com:1234
+#
+# The target definition file will get used if and only if the
+# qRegisterInfo packets are not supported when connecting to a remote
+# GDB server.
+#----------------------------------------------------------------------
+from lldb import *
+
+# Compiler and DWARF register numbers
+name_to_gcc_dwarf_regnum = {
+ 'rax' : 0 ,
+ 'rdx' : 1 ,
+ 'rcx' : 2 ,
+ 'rbx' : 3 ,
+ 'rsi' : 4 ,
+ 'rdi' : 5 ,
+ 'rbp' : 6 ,
+ 'rsp' : 7 ,
+ 'r8' : 8 ,
+ 'r9' : 9 ,
+ 'r10' : 10,
+ 'r11' : 11,
+ 'r12' : 12,
+ 'r13' : 13,
+ 'r14' : 14,
+ 'r15' : 15,
+ 'rip' : 16,
+ 'xmm0' : 17,
+ 'xmm1' : 18,
+ 'xmm2' : 19,
+ 'xmm3' : 20,
+ 'xmm4' : 21,
+ 'xmm5' : 22,
+ 'xmm6' : 23,
+ 'xmm7' : 24,
+ 'xmm8' : 25,
+ 'xmm9' : 26,
+ 'xmm10' : 27,
+ 'xmm11' : 28,
+ 'xmm12' : 29,
+ 'xmm13' : 30,
+ 'xmm14' : 31,
+ 'xmm15' : 32,
+ 'stmm0' : 33,
+ 'stmm1' : 34,
+ 'stmm2' : 35,
+ 'stmm3' : 36,
+ 'stmm4' : 37,
+ 'stmm5' : 38,
+ 'stmm6' : 39,
+ 'stmm7' : 30,
+ 'ymm0' : 41,
+ 'ymm1' : 42,
+ 'ymm2' : 43,
+ 'ymm3' : 44,
+ 'ymm4' : 45,
+ 'ymm5' : 46,
+ 'ymm6' : 47,
+ 'ymm7' : 48,
+ 'ymm8' : 49,
+ 'ymm9' : 40,
+ 'ymm10' : 41,
+ 'ymm11' : 42,
+ 'ymm12' : 43,
+ 'ymm13' : 44,
+ 'ymm14' : 45,
+ 'ymm15' : 46
+};
+
+name_to_gdb_regnum = {
+ 'rax' : 0,
+ 'rbx' : 1,
+ 'rcx' : 2,
+ 'rdx' : 3,
+ 'rsi' : 4,
+ 'rdi' : 5,
+ 'rbp' : 6,
+ 'rsp' : 7,
+ 'r8' : 8,
+ 'r9' : 9,
+ 'r10' : 10,
+ 'r11' : 11,
+ 'r12' : 12,
+ 'r13' : 13,
+ 'r14' : 14,
+ 'r15' : 15,
+ 'rip' : 16,
+ 'rflags': 17,
+ 'cs' : 18,
+ 'ss' : 19,
+ 'ds' : 20,
+ 'es' : 21,
+ 'fs' : 22,
+ 'gs' : 23,
+ 'stmm0' : 24,
+ 'stmm1' : 25,
+ 'stmm2' : 26,
+ 'stmm3' : 27,
+ 'stmm4' : 28,
+ 'stmm5' : 29,
+ 'stmm6' : 30,
+ 'stmm7' : 31,
+ 'fctrl' : 32,
+ 'fstat' : 33,
+ 'ftag' : 34,
+ 'fiseg' : 35,
+ 'fioff' : 36,
+ 'foseg' : 37,
+ 'fooff' : 38,
+ 'fop' : 39,
+ 'xmm0' : 40,
+ 'xmm1' : 41,
+ 'xmm2' : 42,
+ 'xmm3' : 43,
+ 'xmm4' : 44,
+ 'xmm5' : 45,
+ 'xmm6' : 46,
+ 'xmm7' : 47,
+ 'xmm8' : 48,
+ 'xmm9' : 49,
+ 'xmm10' : 50,
+ 'xmm11' : 51,
+ 'xmm12' : 52,
+ 'xmm13' : 53,
+ 'xmm14' : 54,
+ 'xmm15' : 55,
+ 'mxcsr' : 56,
+ 'ymm0' : 57,
+ 'ymm1' : 58,
+ 'ymm2' : 59,
+ 'ymm3' : 60,
+ 'ymm4' : 61,
+ 'ymm5' : 62,
+ 'ymm6' : 63,
+ 'ymm7' : 64,
+ 'ymm8' : 65,
+ 'ymm9' : 66,
+ 'ymm10' : 67,
+ 'ymm11' : 68,
+ 'ymm12' : 69,
+ 'ymm13' : 70,
+ 'ymm14' : 71,
+ 'ymm15' : 72
+};
+
+name_to_generic_regnum = {
+ 'rip' : LLDB_REGNUM_GENERIC_PC,
+ 'rsp' : LLDB_REGNUM_GENERIC_SP,
+ 'rbp' : LLDB_REGNUM_GENERIC_FP,
+ 'rdi' : LLDB_REGNUM_GENERIC_ARG1,
+ 'rsi' : LLDB_REGNUM_GENERIC_ARG2,
+ 'rdx' : LLDB_REGNUM_GENERIC_ARG3,
+ 'rcx' : LLDB_REGNUM_GENERIC_ARG4,
+ 'r8' : LLDB_REGNUM_GENERIC_ARG5,
+ 'r9' : LLDB_REGNUM_GENERIC_ARG6
+};
+
+
+def get_reg_num (reg_num_dict, reg_name):
+ if reg_name in reg_num_dict:
+ return reg_num_dict[reg_name]
+ return LLDB_INVALID_REGNUM
+
+def get_reg_num (reg_num_dict, reg_name):
+ if reg_name in reg_num_dict:
+ return reg_num_dict[reg_name]
+ return LLDB_INVALID_REGNUM
+
+x86_64_register_infos = [
+{ 'name':'rax' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo },
+{ 'name':'rbx' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo },
+{ 'name':'rcx' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo, 'alt-name':'arg4' },
+{ 'name':'rdx' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo, 'alt-name':'arg3' },
+{ 'name':'rsi' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo, 'alt-name':'arg2' },
+{ 'name':'rdi' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo, 'alt-name':'arg1' },
+{ 'name':'rbp' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo, 'alt-name':'fp' },
+{ 'name':'rsp' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo, 'alt-name':'sp' },
+{ 'name':'r8' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo, 'alt-name':'arg5' },
+{ 'name':'r9' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo, 'alt-name':'arg6' },
+{ 'name':'r10' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo },
+{ 'name':'r11' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo },
+{ 'name':'r12' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo },
+{ 'name':'r13' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo },
+{ 'name':'r14' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo },
+{ 'name':'r15' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo },
+{ 'name':'rip' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo, 'alt-name':'pc' },
+{ 'name':'rflags', 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
+{ 'name':'cs' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
+{ 'name':'ss' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
+{ 'name':'ds' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
+{ 'name':'es' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
+{ 'name':'fs' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
+{ 'name':'gs' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
+{ 'name':'stmm0' , 'set':1, 'bitsize':80 , 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'stmm1' , 'set':1, 'bitsize':80 , 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'stmm2' , 'set':1, 'bitsize':80 , 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'stmm3' , 'set':1, 'bitsize':80 , 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'stmm4' , 'set':1, 'bitsize':80 , 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'stmm5' , 'set':1, 'bitsize':80 , 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'stmm6' , 'set':1, 'bitsize':80 , 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'stmm7' , 'set':1, 'bitsize':80 , 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'fctrl' , 'set':1, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
+{ 'name':'fstat' , 'set':1, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
+{ 'name':'ftag' , 'set':1, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
+{ 'name':'fiseg' , 'set':1, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
+{ 'name':'fioff' , 'set':1, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
+{ 'name':'foseg' , 'set':1, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
+{ 'name':'fooff' , 'set':1, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
+{ 'name':'fop' , 'set':1, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
+{ 'name':'xmm0' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'xmm1' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'xmm2' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'xmm3' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'xmm4' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'xmm5' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'xmm6' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'xmm7' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'xmm8' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'xmm9' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'xmm10' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'xmm11' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'xmm12' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'xmm13' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'xmm14' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'xmm15' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
+{ 'name':'mxcsr' , 'set':1, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
+# Registers that are contained in or composed of one of more other registers
+{ 'name':'eax' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rax[31:0]' },
+{ 'name':'ebx' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rbx[31:0]' },
+{ 'name':'ecx' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rcx[31:0]' },
+{ 'name':'edx' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rdx[31:0]' },
+{ 'name':'edi' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rdi[31:0]' },
+{ 'name':'esi' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rsi[31:0]' },
+{ 'name':'ebp' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rbp[31:0]' },
+{ 'name':'esp' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rsp[31:0]' },
+{ 'name':'r8d' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r8[31:0]' },
+{ 'name':'r9d' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r9[31:0]' },
+{ 'name':'r10d' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r10[31:0]' },
+{ 'name':'r11d' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r11[31:0]' },
+{ 'name':'r12d' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r12[31:0]' },
+{ 'name':'r13d' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r13[31:0]' },
+{ 'name':'r14d' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r14[31:0]' },
+{ 'name':'r15d' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r15[31:0]' },
+
+{ 'name':'ax' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rax[15:0]' },
+{ 'name':'bx' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rbx[15:0]' },
+{ 'name':'cx' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rcx[15:0]' },
+{ 'name':'dx' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rdx[15:0]' },
+{ 'name':'di' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rdi[15:0]' },
+{ 'name':'si' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rsi[15:0]' },
+{ 'name':'bp' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rbp[15:0]' },
+{ 'name':'sp' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rsp[15:0]' },
+{ 'name':'r8w' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r8[15:0]' },
+{ 'name':'r9w' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r9[15:0]' },
+{ 'name':'r10w' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r10[15:0]' },
+{ 'name':'r11w' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r11[15:0]' },
+{ 'name':'r12w' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r12[15:0]' },
+{ 'name':'r13w' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r13[15:0]' },
+{ 'name':'r14w' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r14[15:0]' },
+{ 'name':'r15w' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r15[15:0]' },
+
+{ 'name':'ah' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rax[15:8]' },
+{ 'name':'bh' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rbx[15:8]' },
+{ 'name':'ch' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rcx[15:8]' },
+{ 'name':'dh' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rdx[15:8]' },
+
+{ 'name':'al' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rax[7:0]' },
+{ 'name':'bl' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rbx[7:0]' },
+{ 'name':'cl' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rcx[7:0]' },
+{ 'name':'dl' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rdx[7:0]' },
+{ 'name':'dil' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rdi[7:0]' },
+{ 'name':'sil' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rsi[7:0]' },
+{ 'name':'bpl' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rbp[7:0]' },
+{ 'name':'spl' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rsp[7:0]' },
+{ 'name':'r8l' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r8[7:0]' },
+{ 'name':'r9l' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r9[7:0]' },
+{ 'name':'r10l' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r10[7:0]' },
+{ 'name':'r11l' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r11[7:0]' },
+{ 'name':'r12l' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r12[7:0]' },
+{ 'name':'r13l' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r13[7:0]' },
+{ 'name':'r14l' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r14[7:0]' },
+{ 'name':'r15l' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r15[7:0]' },
+];
+
+g_target_definition = None
+
+def get_target_definition ():
+ global g_target_definition
+ if g_target_definition == None:
+ g_target_definition = {}
+ offset = 0
+ for reg_info in x86_64_register_infos:
+ reg_name = reg_info['name']
+
+ # Only fill in the offset if there is no 'slice' in the register info
+ if 'slice' not in reg_info and 'composite' not in reg_info:
+ reg_info['offset'] = offset
+ offset += reg_info['bitsize']/8
+
+ # Set the GCC/DWARF register number for this register if it has one
+ reg_num = get_reg_num(name_to_gcc_dwarf_regnum, reg_name)
+ if reg_num != LLDB_INVALID_REGNUM:
+ reg_info['gcc'] = reg_num
+ reg_info['dwarf'] = reg_num
+
+ # Set the generic register number for this register if it has one
+ reg_num = get_reg_num(name_to_generic_regnum, reg_name)
+ if reg_num != LLDB_INVALID_REGNUM:
+ reg_info['generic'] = reg_num
+
+ # Set the GDB register number for this register if it has one
+ reg_num = get_reg_num(name_to_gdb_regnum, reg_name)
+ if reg_num != LLDB_INVALID_REGNUM:
+ reg_info['gdb'] = reg_num
+
+ g_target_definition['sets'] = ['General Purpose Registers', 'Floating Point Registers']
+ g_target_definition['registers'] = x86_64_register_infos
+ g_target_definition['host-info'] = { 'triple' : 'x86_64-apple-macosx', 'endian': eByteOrderLittle }
+ g_target_definition['g-packet-size'] = offset
+ return g_target_definition
+
+def get_dynamic_setting(target, setting_name):
+ if setting_name == 'gdb-server-target-definition':
+ return get_target_definition() \ No newline at end of file