<div dir="ltr">Can you explain this? Why are we upstreaming a second copy of SB headers and clang headers? This looks like something that should be out of tree</div><br><div class="gmail_quote"><div dir="ltr">On Tue, Dec 15, 2015 at 3:06 PM Greg Clayton via lldb-commits <<a href="mailto:lldb-commits@lists.llvm.org">lldb-commits@lists.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Added: lldb/trunk/build/Debug/LLDB.framework/Versions/A/Resources/Python/lldb/macosx/crashlog.py<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lldb/trunk/build/Debug/LLDB.framework/Versions/A/Resources/Python/lldb/macosx/crashlog.py?rev=255697&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lldb/trunk/build/Debug/LLDB.framework/Versions/A/Resources/Python/lldb/macosx/crashlog.py?rev=255697&view=auto</a><br>
==============================================================================<br>
--- lldb/trunk/build/Debug/LLDB.framework/Versions/A/Resources/Python/lldb/macosx/crashlog.py (added)<br>
+++ lldb/trunk/build/Debug/LLDB.framework/Versions/A/Resources/Python/lldb/macosx/crashlog.py Tue Dec 15 17:03:22 2015<br>
@@ -0,0 +1,829 @@<br>
+#!/usr/bin/python<br>
+<br>
+#----------------------------------------------------------------------<br>
+# Be sure to add the python path that points to the LLDB shared library.<br>
+#<br>
+# To use this in the embedded python interpreter using "lldb":<br>
+#<br>
+# cd /path/containing/crashlog.py<br>
+# lldb<br>
+# (lldb) script import crashlog<br>
+# "crashlog" command installed, type "crashlog --help" for detailed help<br>
+# (lldb) crashlog ~/Library/Logs/DiagnosticReports/a.crash<br>
+#<br>
+# The benefit of running the crashlog command inside lldb in the<br>
+# embedded python interpreter is when the command completes, there<br>
+# will be a target with all of the files loaded at the locations<br>
+# described in the crash log. Only the files that have stack frames<br>
+# in the backtrace will be loaded unless the "--load-all" option<br>
+# has been specified. This allows users to explore the program in the<br>
+# state it was in right at crash time.<br>
+#<br>
+# On MacOSX csh, tcsh:<br>
+# ( setenv PYTHONPATH /path/to/LLDB.framework/Resources/Python ; ./crashlog.py ~/Library/Logs/DiagnosticReports/a.crash )<br>
+#<br>
+# On MacOSX sh, bash:<br>
+# PYTHONPATH=/path/to/LLDB.framework/Resources/Python ./crashlog.py ~/Library/Logs/DiagnosticReports/a.crash<br>
+#----------------------------------------------------------------------<br>
+<br>
+import commands<br>
+import cmd<br>
+import datetime<br>
+import glob<br>
+import optparse<br>
+import os<br>
+import platform<br>
+import plistlib<br>
+import pprint # pp = pprint.PrettyPrinter(indent=4); pp.pprint(command_args)<br>
+import re<br>
+import shlex<br>
+import string<br>
+import sys<br>
+import time<br>
+import uuid<br>
+<br>
+try:<br>
+ # Just try for LLDB in case PYTHONPATH is already correctly setup<br>
+ import lldb<br>
+except ImportError:<br>
+ lldb_python_dirs = list()<br>
+ # lldb is not in the PYTHONPATH, try some defaults for the current platform<br>
+ platform_system = platform.system()<br>
+ if platform_system == 'Darwin':<br>
+ # On Darwin, try the currently selected Xcode directory<br>
+ xcode_dir = commands.getoutput("xcode-select --print-path")<br>
+ if xcode_dir:<br>
+ lldb_python_dirs.append(os.path.realpath(xcode_dir + '/../SharedFrameworks/LLDB.framework/Resources/Python'))<br>
+ lldb_python_dirs.append(xcode_dir + '/Library/PrivateFrameworks/LLDB.framework/Resources/Python')<br>
+ lldb_python_dirs.append('/System/Library/PrivateFrameworks/LLDB.framework/Resources/Python')<br>
+ success = False<br>
+ for lldb_python_dir in lldb_python_dirs:<br>
+ if os.path.exists(lldb_python_dir):<br>
+ if not (sys.path.__contains__(lldb_python_dir)):<br>
+ sys.path.append(lldb_python_dir)<br>
+ try:<br>
+ import lldb<br>
+ except ImportError:<br>
+ pass<br>
+ else:<br>
+ print 'imported lldb from: "%s"' % (lldb_python_dir)<br>
+ success = True<br>
+ break<br>
+ if not success:<br>
+ print "error: couldn't locate the 'lldb' module, please set PYTHONPATH correctly"<br>
+ sys.exit(1)<br>
+<br>
+from lldb.utils import symbolication<br>
+<br>
+PARSE_MODE_NORMAL = 0<br>
+PARSE_MODE_THREAD = 1<br>
+PARSE_MODE_IMAGES = 2<br>
+PARSE_MODE_THREGS = 3<br>
+PARSE_MODE_SYSTEM = 4<br>
+<br>
+class CrashLog(symbolication.Symbolicator):<br>
+ """Class that does parses darwin crash logs"""<br>
+ parent_process_regex = re.compile('^Parent Process:\s*(.*)\[(\d+)\]');<br>
+ thread_state_regex = re.compile('^Thread ([0-9]+) crashed with')<br>
+ thread_regex = re.compile('^Thread ([0-9]+)([^:]*):(.*)')<br>
+ app_backtrace_regex = re.compile('^Application Specific Backtrace ([0-9]+)([^:]*):(.*)')<br>
+ frame_regex = re.compile('^([0-9]+)\s+([^ ]+)\s+(0x[0-9a-fA-F]+) +(.*)')<br>
+ image_regex_uuid = re.compile('(0x[0-9a-fA-F]+)[- ]+(0x[0-9a-fA-F]+) +[+]?([^ ]+) +([^<]+)<([-0-9a-fA-F]+)> (.*)');<br>
+ image_regex_no_uuid = re.compile('(0x[0-9a-fA-F]+)[- ]+(0x[0-9a-fA-F]+) +[+]?([^ ]+) +([^/]+)/(.*)');<br>
+ empty_line_regex = re.compile('^$')<br>
+<br>
+ class Thread:<br>
+ """Class that represents a thread in a darwin crash log"""<br>
+ def __init__(self, index, app_specific_backtrace):<br>
+ self.index = index<br>
+ self.frames = list()<br>
+ self.idents = list()<br>
+ self.registers = dict()<br>
+ self.reason = None<br>
+ self.queue = None<br>
+ self.app_specific_backtrace = app_specific_backtrace<br>
+<br>
+ def dump(self, prefix):<br>
+ if self.app_specific_backtrace:<br>
+ print "%Application Specific Backtrace[%u] %s" % (prefix, self.index, self.reason)<br>
+ else:<br>
+ print "%sThread[%u] %s" % (prefix, self.index, self.reason)<br>
+ if self.frames:<br>
+ print "%s Frames:" % (prefix)<br>
+ for frame in self.frames:<br>
+ frame.dump(prefix + ' ')<br>
+ if self.registers:<br>
+ print "%s Registers:" % (prefix)<br>
+ for reg in self.registers.keys():<br>
+ print "%s %-5s = %#16.16x" % (prefix, reg, self.registers[reg])<br>
+<br>
+ def dump_symbolicated (self, crash_log, options):<br>
+ this_thread_crashed = self.app_specific_backtrace<br>
+ if not this_thread_crashed:<br>
+ this_thread_crashed = self.did_crash()<br>
+ if options.crashed_only and this_thread_crashed == False:<br>
+ return<br>
+<br>
+ print "%s" % self<br>
+ #prev_frame_index = -1<br>
+ display_frame_idx = -1<br>
+ for frame_idx, frame in enumerate(self.frames):<br>
+ disassemble = (this_thread_crashed or options.disassemble_all_threads) and frame_idx < options.disassemble_depth;<br>
+ if frame_idx == 0:<br>
+ symbolicated_frame_addresses = crash_log.symbolicate (frame.pc & crash_log.addr_mask, options.verbose)<br>
+ else:<br>
+ # Any frame above frame zero and we have to subtract one to get the previous line entry<br>
+ symbolicated_frame_addresses = crash_log.symbolicate ((frame.pc & crash_log.addr_mask) - 1, options.verbose)<br>
+<br>
+ if symbolicated_frame_addresses:<br>
+ symbolicated_frame_address_idx = 0<br>
+ for symbolicated_frame_address in symbolicated_frame_addresses:<br>
+ display_frame_idx += 1<br>
+ print '[%3u] %s' % (frame_idx, symbolicated_frame_address)<br>
+ if (options.source_all or self.did_crash()) and display_frame_idx < options.source_frames and options.source_context:<br>
+ source_context = options.source_context<br>
+ line_entry = symbolicated_frame_address.get_symbol_context().line_entry<br>
+ if line_entry.IsValid():<br>
+ strm = lldb.SBStream()<br>
+ if line_entry:<br>
+ lldb.debugger.GetSourceManager().DisplaySourceLinesWithLineNumbers(line_entry.file, line_entry.line, source_context, source_context, "->", strm)<br>
+ source_text = strm.GetData()<br>
+ if source_text:<br>
+ # Indent the source a bit<br>
+ indent_str = ' '<br>
+ join_str = '\n' + indent_str<br>
+ print '%s%s' % (indent_str, join_str.join(source_text.split('\n')))<br>
+ if symbolicated_frame_address_idx == 0:<br>
+ if disassemble:<br>
+ instructions = symbolicated_frame_address.get_instructions()<br>
+ if instructions:<br>
+ print<br>
+ symbolication.disassemble_instructions (crash_log.get_target(),<br>
+ instructions,<br>
+ frame.pc,<br>
+ options.disassemble_before,<br>
+ options.disassemble_after, frame.index > 0)<br>
+ print<br>
+ symbolicated_frame_address_idx += 1<br>
+ else:<br>
+ print frame<br>
+<br>
+ def add_ident(self, ident):<br>
+ if not ident in self.idents:<br>
+ self.idents.append(ident)<br>
+<br>
+ def did_crash(self):<br>
+ return self.reason != None<br>
+<br>
+ def __str__(self):<br>
+ if self.app_specific_backtrace:<br>
+ s = "Application Specific Backtrace[%u]" % self.index<br>
+ else:<br>
+ s = "Thread[%u]" % self.index<br>
+ if self.reason:<br>
+ s += ' %s' % self.reason<br>
+ return s<br>
+<br>
+<br>
+ class Frame:<br>
+ """Class that represents a stack frame in a thread in a darwin crash log"""<br>
+ def __init__(self, index, pc, description):<br>
+ self.pc = pc<br>
+ self.description = description<br>
+ self.index = index<br>
+<br>
+ def __str__(self):<br>
+ if self.description:<br>
+ return "[%3u] 0x%16.16x %s" % (self.index, self.pc, self.description)<br>
+ else:<br>
+ return "[%3u] 0x%16.16x" % (self.index, self.pc)<br>
+<br>
+ def dump(self, prefix):<br>
+ print "%s%s" % (prefix, str(self))<br>
+<br>
+ class DarwinImage(symbolication.Image):<br>
+ """Class that represents a binary images in a darwin crash log"""<br>
+ dsymForUUIDBinary = os.path.expanduser('~rc/bin/dsymForUUID')<br>
+ if not os.path.exists(dsymForUUIDBinary):<br>
+ dsymForUUIDBinary = commands.getoutput('which dsymForUUID')<br>
+<br>
+ dwarfdump_uuid_regex = re.compile('UUID: ([-0-9a-fA-F]+) \(([^\(]+)\) .*')<br>
+<br>
+ def __init__(self, text_addr_lo, text_addr_hi, identifier, version, uuid, path):<br>
+ symbolication.Image.__init__(self, path, uuid);<br>
+ self.add_section (symbolication.Section(text_addr_lo, text_addr_hi, "__TEXT"))<br>
+ self.identifier = identifier<br>
+ self.version = version<br>
+<br>
+ def locate_module_and_debug_symbols(self):<br>
+ # Don't load a module twice...<br>
+ if self.resolved:<br>
+ return True<br>
+ # Mark this as resolved so we don't keep trying<br>
+ self.resolved = True<br>
+ uuid_str = self.get_normalized_uuid_string()<br>
+ print 'Getting symbols for %s %s...' % (uuid_str, self.path),<br>
+ if os.path.exists(self.dsymForUUIDBinary):<br>
+ dsym_for_uuid_command = '%s %s' % (self.dsymForUUIDBinary, uuid_str)<br>
+ s = commands.getoutput(dsym_for_uuid_command)<br>
+ if s:<br>
+ plist_root = plistlib.readPlistFromString (s)<br>
+ if plist_root:<br>
+ plist = plist_root[uuid_str]<br>
+ if plist:<br>
+ if 'DBGArchitecture' in plist:<br>
+ self.arch = plist['DBGArchitecture']<br>
+ if 'DBGDSYMPath' in plist:<br>
+ self.symfile = os.path.realpath(plist['DBGDSYMPath'])<br>
+ if 'DBGSymbolRichExecutable' in plist:<br>
+ self.path = os.path.expanduser (plist['DBGSymbolRichExecutable'])<br>
+ self.resolved_path = self.path<br>
+ if not self.resolved_path and os.path.exists(self.path):<br>
+ dwarfdump_cmd_output = commands.getoutput('dwarfdump --uuid "%s"' % self.path)<br>
+ self_uuid = self.get_uuid()<br>
+ for line in dwarfdump_cmd_output.splitlines():<br>
+ match = self.dwarfdump_uuid_regex.search (line)<br>
+ if match:<br>
+ dwarf_uuid_str = match.group(1)<br>
+ dwarf_uuid = uuid.UUID(dwarf_uuid_str)<br>
+ if self_uuid == dwarf_uuid:<br>
+ self.resolved_path = self.path<br>
+ self.arch = match.group(2)<br>
+ break;<br>
+ if not self.resolved_path:<br>
+ self.unavailable = True<br>
+ print "error\n error: unable to locate '%s' with UUID %s" % (self.path, uuid_str)<br>
+ return False<br>
+ if (self.resolved_path and os.path.exists(self.resolved_path)) or (self.path and os.path.exists(self.path)):<br>
+ print 'ok'<br>
+ # if self.resolved_path:<br>
+ # print ' exe = "%s"' % self.resolved_path<br>
+ # if self.symfile:<br>
+ # print ' dsym = "%s"' % self.symfile<br>
+ return True<br>
+ else:<br>
+ self.unavailable = True<br>
+ return False<br>
+<br>
+<br>
+<br>
+ def __init__(self, path):<br>
+ """CrashLog constructor that take a path to a darwin crash log file"""<br>
+ symbolication.Symbolicator.__init__(self);<br>
+ self.path = os.path.expanduser(path);<br>
+ self.info_lines = list()<br>
+ self.system_profile = list()<br>
+ self.threads = list()<br>
+ self.backtraces = list() # For application specific backtraces<br>
+ self.idents = list() # A list of the required identifiers for doing all stack backtraces<br>
+ self.crashed_thread_idx = -1<br>
+ self.version = -1<br>
+ self.error = None<br>
+ self.target = None<br>
+ # With possible initial component of ~ or ~user replaced by that user's home directory.<br>
+ try:<br>
+ f = open(self.path)<br>
+ except IOError:<br>
+ self.error = 'error: cannot open "%s"' % self.path<br>
+ return<br>
+<br>
+ self.file_lines = f.read().splitlines()<br>
+ parse_mode = PARSE_MODE_NORMAL<br>
+ thread = None<br>
+ app_specific_backtrace = False<br>
+ for line in self.file_lines:<br>
+ # print line<br>
+ line_len = len(line)<br>
+ if line_len == 0:<br>
+ if thread:<br>
+ if parse_mode == PARSE_MODE_THREAD:<br>
+ if thread.index == self.crashed_thread_idx:<br>
+ thread.reason = ''<br>
+ if self.thread_exception:<br>
+ thread.reason += self.thread_exception<br>
+ if self.thread_exception_data:<br>
+ thread.reason += " (%s)" % self.thread_exception_data<br>
+ if app_specific_backtrace:<br>
+ self.backtraces.append(thread)<br>
+ else:<br>
+ self.threads.append(thread)<br>
+ thread = None<br>
+ else:<br>
+ # only append an extra empty line if the previous line<br>
+ # in the info_lines wasn't empty<br>
+ if len(self.info_lines) > 0 and len(self.info_lines[-1]):<br>
+ self.info_lines.append(line)<br>
+ parse_mode = PARSE_MODE_NORMAL<br>
+ # print 'PARSE_MODE_NORMAL'<br>
+ elif parse_mode == PARSE_MODE_NORMAL:<br>
+ if line.startswith ('Process:'):<br>
+ (self.process_name, pid_with_brackets) = line[8:].strip().split(' [')<br>
+ self.process_id = pid_with_brackets.strip('[]')<br>
+ elif line.startswith ('Path:'):<br>
+ self.process_path = line[5:].strip()<br>
+ elif line.startswith ('Identifier:'):<br>
+ self.process_identifier = line[11:].strip()<br>
+ elif line.startswith ('Version:'):<br>
+ version_string = line[8:].strip()<br>
+ matched_pair = re.search("(.+)\((.+)\)", version_string)<br>
+ if matched_pair:<br>
+ self.process_version = matched_pair.group(1)<br>
+ self.process_compatability_version = matched_pair.group(2)<br>
+ else:<br>
+ self.process = version_string<br>
+ self.process_compatability_version = version_string<br>
+ elif self.parent_process_regex.search(line):<br>
+ parent_process_match = self.parent_process_regex.search(line)<br>
+ self.parent_process_name = parent_process_match.group(1)<br>
+ self.parent_process_id = parent_process_match.group(2)<br>
+ elif line.startswith ('Exception Type:'):<br>
+ self.thread_exception = line[15:].strip()<br>
+ continue<br>
+ elif line.startswith ('Exception Codes:'):<br>
+ self.thread_exception_data = line[16:].strip()<br>
+ continue<br>
+ elif line.startswith ('Crashed Thread:'):<br>
+ self.crashed_thread_idx = int(line[15:].strip().split()[0])<br>
+ continue<br>
+ elif line.startswith ('Report Version:'):<br>
+ self.version = int(line[15:].strip())<br>
+ continue<br>
+ elif line.startswith ('System Profile:'):<br>
+ parse_mode = PARSE_MODE_SYSTEM<br>
+ continue<br>
+ elif (line.startswith ('Interval Since Last Report:') or<br>
+ line.startswith ('Crashes Since Last Report:') or<br>
+ line.startswith ('Per-App Interval Since Last Report:') or<br>
+ line.startswith ('Per-App Crashes Since Last Report:') or<br>
+ line.startswith ('Sleep/Wake UUID:') or<br>
+ line.startswith ('Anonymous UUID:')):<br>
+ # ignore these<br>
+ continue<br>
+ elif line.startswith ('Thread'):<br>
+ thread_state_match = self.thread_state_regex.search (line)<br>
+ if thread_state_match:<br>
+ app_specific_backtrace = False<br>
+ thread_state_match = self.thread_regex.search (line)<br>
+ thread_idx = int(thread_state_match.group(1))<br>
+ parse_mode = PARSE_MODE_THREGS<br>
+ thread = self.threads[thread_idx]<br>
+ else:<br>
+ thread_match = self.thread_regex.search (line)<br>
+ if thread_match:<br>
+ app_specific_backtrace = False<br>
+ parse_mode = PARSE_MODE_THREAD<br>
+ thread_idx = int(thread_match.group(1))<br>
+ thread = CrashLog.Thread(thread_idx, False)<br>
+ continue<br>
+ elif line.startswith ('Binary Images:'):<br>
+ parse_mode = PARSE_MODE_IMAGES<br>
+ continue<br>
+ elif line.startswith ('Application Specific Backtrace'):<br>
+ app_backtrace_match = self.app_backtrace_regex.search (line)<br>
+ if app_backtrace_match:<br>
+ parse_mode = PARSE_MODE_THREAD<br>
+ app_specific_backtrace = True<br>
+ idx = int(app_backtrace_match.group(1))<br>
+ thread = CrashLog.Thread(idx, True)<br>
+ self.info_lines.append(line.strip())<br>
+ elif parse_mode == PARSE_MODE_THREAD:<br>
+ if line.startswith ('Thread'):<br>
+ continue<br>
+ frame_match = self.frame_regex.search(line)<br>
+ if frame_match:<br>
+ ident = frame_match.group(2)<br>
+ thread.add_ident(ident)<br>
+ if not ident in self.idents:<br>
+ self.idents.append(ident)<br>
+ thread.frames.append (CrashLog.Frame(int(frame_match.group(1)), int(frame_match.group(3), 0), frame_match.group(4)))<br>
+ else:<br>
+ print 'error: frame regex failed for line: "%s"' % line<br>
+ elif parse_mode == PARSE_MODE_IMAGES:<br>
+ image_match = self.image_regex_uuid.search (line)<br>
+ if image_match:<br>
+ image = CrashLog.DarwinImage (int(image_match.group(1),0),<br>
+ int(image_match.group(2),0),<br>
+ image_match.group(3).strip(),<br>
+ image_match.group(4).strip(),<br>
+ uuid.UUID(image_match.group(5)),<br>
+ image_match.group(6))<br>
+ self.images.append (image)<br>
+ else:<br>
+ image_match = self.image_regex_no_uuid.search (line)<br>
+ if image_match:<br>
+ image = CrashLog.DarwinImage (int(image_match.group(1),0),<br>
+ int(image_match.group(2),0),<br>
+ image_match.group(3).strip(),<br>
+ image_match.group(4).strip(),<br>
+ None,<br>
+ image_match.group(5))<br>
+ self.images.append (image)<br>
+ else:<br>
+ print "error: image regex failed for: %s" % line<br>
+<br>
+ elif parse_mode == PARSE_MODE_THREGS:<br>
+ stripped_line = line.strip()<br>
+ # "r12: 0x00007fff6b5939c8 r13: 0x0000000007000006 r14: 0x0000000000002a03 r15: 0x0000000000000c00"<br>
+ reg_values = re.findall ('([a-zA-Z0-9]+: 0[Xx][0-9a-fA-F]+) *', stripped_line);<br>
+ for reg_value in reg_values:<br>
+ #print 'reg_value = "%s"' % reg_value<br>
+ (reg, value) = reg_value.split(': ')<br>
+ #print 'reg = "%s"' % reg<br>
+ #print 'value = "%s"' % value<br>
+ thread.registers[reg.strip()] = int(value, 0)<br>
+ elif parse_mode == PARSE_MODE_SYSTEM:<br>
+ self.system_profile.append(line)<br>
+ f.close()<br>
+<br>
+ def dump(self):<br>
+ print "Crash Log File: %s" % (self.path)<br>
+ if self.backtraces:<br>
+ print "\nApplication Specific Backtraces:"<br>
+ for thread in self.backtraces:<br>
+ thread.dump(' ')<br>
+ print "\nThreads:"<br>
+ for thread in self.threads:<br>
+ thread.dump(' ')<br>
+ print "\nImages:"<br>
+ for image in self.images:<br>
+ image.dump(' ')<br>
+<br>
+ def find_image_with_identifier(self, identifier):<br>
+ for image in self.images:<br>
+ if image.identifier == identifier:<br>
+ return image<br>
+ regex_text = '^.*\.%s$' % (identifier)<br>
+ regex = re.compile(regex_text)<br>
+ for image in self.images:<br>
+ if regex.match(image.identifier):<br>
+ return image<br>
+ return None<br>
+<br>
+ def create_target(self):<br>
+ #print 'crashlog.create_target()...'<br>
+ if self.target is None:<br>
+ self.target = symbolication.Symbolicator.create_target(self)<br>
+ if self.target:<br>
+ return self.target<br>
+ # We weren't able to open the main executable as, but we can still symbolicate<br>
+ print 'crashlog.create_target()...2'<br>
+ if self.idents:<br>
+ for ident in self.idents:<br>
+ image = self.find_image_with_identifier (ident)<br>
+ if image:<br>
+ self.target = image.create_target ()<br>
+ if self.target:<br>
+ return self.target # success<br>
+ print 'crashlog.create_target()...3'<br>
+ for image in self.images:<br>
+ self.target = image.create_target ()<br>
+ if self.target:<br>
+ return self.target # success<br>
+ print 'crashlog.create_target()...4'<br>
+ print 'error: unable to locate any executables from the crash log'<br>
+ return self.target<br>
+<br>
+ def get_target(self):<br>
+ return self.target<br>
+<br>
+def usage():<br>
+ print "Usage: lldb-symbolicate.py [-n name] executable-image"<br>
+ sys.exit(0)<br>
+<br>
+class Interactive(cmd.Cmd):<br>
+ '''Interactive prompt for analyzing one or more Darwin crash logs, type "help" to see a list of supported commands.'''<br>
+ image_option_parser = None<br>
+<br>
+ def __init__(self, crash_logs):<br>
+ cmd.Cmd.__init__(self)<br>
+ self.use_rawinput = False<br>
+ self.intro = 'Interactive crashlogs prompt, type "help" to see a list of supported commands.'<br>
+ self.crash_logs = crash_logs<br>
+ self.prompt = '% '<br>
+<br>
+ def default(self, line):<br>
+ '''Catch all for unknown command, which will exit the interpreter.'''<br>
+ print "uknown command: %s" % line<br>
+ return True<br>
+<br>
+ def do_q(self, line):<br>
+ '''Quit command'''<br>
+ return True<br>
+<br>
+ def do_quit(self, line):<br>
+ '''Quit command'''<br>
+ return True<br>
+<br>
+ def do_symbolicate(self, line):<br>
+ description='''Symbolicate one or more darwin crash log files by index to provide source file and line information,<br>
+ inlined stack frames back to the concrete functions, and disassemble the location of the crash<br>
+ for the first frame of the crashed thread.'''<br>
+ option_parser = CreateSymbolicateCrashLogOptions ('symbolicate', description, False)<br>
+ command_args = shlex.split(line)<br>
+ try:<br>
+ (options, args) = option_parser.parse_args(command_args)<br>
+ except:<br>
+ return<br>
+<br>
+ if args:<br>
+ # We have arguments, they must valid be crash log file indexes<br>
+ for idx_str in args:<br>
+ idx = int(idx_str)<br>
+ if idx < len(self.crash_logs):<br>
+ SymbolicateCrashLog (self.crash_logs[idx], options)<br>
+ else:<br>
+ print 'error: crash log index %u is out of range' % (idx)<br>
+ else:<br>
+ # No arguments, symbolicate all crash logs using the options provided<br>
+ for idx in range(len(self.crash_logs)):<br>
+ SymbolicateCrashLog (self.crash_logs[idx], options)<br>
+<br>
+ def do_list(self, line=None):<br>
+ '''Dump a list of all crash logs that are currently loaded.<br>
+<br>
+ USAGE: list'''<br>
+ print '%u crash logs are loaded:' % len(self.crash_logs)<br>
+ for (crash_log_idx, crash_log) in enumerate(self.crash_logs):<br>
+ print '[%u] = %s' % (crash_log_idx, crash_log.path)<br>
+<br>
+ def do_image(self, line):<br>
+ '''Dump information about one or more binary images in the crash log given an image basename, or all images if no arguments are provided.'''<br>
+ usage = "usage: %prog [options] <PATH> [PATH ...]"<br>
+ 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.'''<br>
+ command_args = shlex.split(line)<br>
+ if not self.image_option_parser:<br>
+ self.image_option_parser = optparse.OptionParser(description=description, prog='image',usage=usage)<br>
+ self.image_option_parser.add_option('-a', '--all', action='store_true', help='show all images', default=False)<br>
+ try:<br>
+ (options, args) = self.image_option_parser.parse_args(command_args)<br>
+ except:<br>
+ return<br>
+<br>
+ if args:<br>
+ for image_path in args:<br>
+ fullpath_search = image_path[0] == '/'<br>
+ for (crash_log_idx, crash_log) in enumerate(self.crash_logs):<br>
+ matches_found = 0<br>
+ for (image_idx, image) in enumerate(crash_log.images):<br>
+ if fullpath_search:<br>
+ if image.get_resolved_path() == image_path:<br>
+ matches_found += 1<br>
+ print '[%u] ' % (crash_log_idx), image<br>
+ else:<br>
+ image_basename = image.get_resolved_path_basename()<br>
+ if image_basename == image_path:<br>
+ matches_found += 1<br>
+ print '[%u] ' % (crash_log_idx), image<br>
+ if matches_found == 0:<br>
+ for (image_idx, image) in enumerate(crash_log.images):<br>
+ resolved_image_path = image.get_resolved_path()<br>
+ if resolved_image_path and string.find(image.get_resolved_path(), image_path) >= 0:<br>
+ print '[%u] ' % (crash_log_idx), image<br>
+ else:<br>
+ for crash_log in self.crash_logs:<br>
+ for (image_idx, image) in enumerate(crash_log.images):<br>
+ print '[%u] %s' % (image_idx, image)<br>
+ return False<br>
+<br>
+<br>
+def interactive_crashlogs(options, args):<br>
+ crash_log_files = list()<br>
+ for arg in args:<br>
+ for resolved_path in glob.glob(arg):<br>
+ crash_log_files.append(resolved_path)<br>
+<br>
+ crash_logs = list();<br>
+ for crash_log_file in crash_log_files:<br>
+ #print 'crash_log_file = "%s"' % crash_log_file<br>
+ crash_log = CrashLog(crash_log_file)<br>
+ if crash_log.error:<br>
+ print crash_log.error<br>
+ continue<br>
+ if options.debug:<br>
+ crash_log.dump()<br>
+ if not crash_log.images:<br>
+ print 'error: no images in crash log "%s"' % (crash_log)<br>
+ continue<br>
+ else:<br>
+ crash_logs.append(crash_log)<br>
+<br>
+ interpreter = Interactive(crash_logs)<br>
+ # List all crash logs that were imported<br>
+ interpreter.do_list()<br>
+ interpreter.cmdloop()<br>
+<br>
+<br>
+def save_crashlog(debugger, command, result, dict):<br>
+ usage = "usage: %prog [options] <output-path>"<br>
+ description='''Export the state of current target into a crashlog file'''<br>
+ parser = optparse.OptionParser(description=description, prog='save_crashlog',usage=usage)<br>
+ parser.add_option('-v', '--verbose', action='store_true', dest='verbose', help='display verbose debug info', default=False)<br>
+ try:<br>
+ (options, args) = parser.parse_args(shlex.split(command))<br>
+ except:<br>
+ result.PutCString ("error: invalid options");<br>
+ return<br>
+ if len(args) != 1:<br>
+ result.PutCString ("error: invalid arguments, a single output file is the only valid argument")<br>
+ return<br>
+ out_file = open(args[0], 'w')<br>
+ if not out_file:<br>
+ result.PutCString ("error: failed to open file '%s' for writing...", args[0]);<br>
+ return<br>
+ target = debugger.GetSelectedTarget()<br>
+ if target:<br>
+ identifier = target.executable.basename<br>
+ if lldb.process:<br>
+ pid = <a href="http://lldb.process.id" rel="noreferrer" target="_blank">lldb.process.id</a><br>
+ if pid != lldb.LLDB_INVALID_PROCESS_ID:<br>
+ out_file.write('Process: %s [%u]\n' % (identifier, pid))<br>
+ out_file.write('Path: %s\n' % (target.executable.fullpath))<br>
+ out_file.write('Identifier: %s\n' % (identifier))<br>
+ out_file.write('\nDate/Time: %s\n' % (datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")))<br>
+ out_file.write('OS Version: Mac OS X %s (%s)\n' % (platform.mac_ver()[0], commands.getoutput('sysctl -n kern.osversion')));<br>
+ out_file.write('Report Version: 9\n')<br>
+ for thread_idx in range(lldb.process.num_threads):<br>
+ thread = lldb.process.thread[thread_idx]<br>
+ out_file.write('\nThread %u:\n' % (thread_idx))<br>
+ for (frame_idx, frame) in enumerate(thread.frames):<br>
+ frame_pc = frame.pc<br>
+ frame_offset = 0<br>
+ if frame.function:<br>
+ block = frame.GetFrameBlock()<br>
+ block_range = block.range[frame.addr]<br>
+ if block_range:<br>
+ block_start_addr = block_range[0]<br>
+ frame_offset = frame_pc - block_start_addr.load_addr<br>
+ else:<br>
+ frame_offset = frame_pc - frame.function.addr.load_addr<br>
+ elif frame.symbol:<br>
+ frame_offset = frame_pc - frame.symbol.addr.load_addr<br>
+ out_file.write('%-3u %-32s 0x%16.16x %s' % (frame_idx, frame.module.file.basename, frame_pc, <a href="http://frame.name" rel="noreferrer" target="_blank">frame.name</a>))<br>
+ if frame_offset > 0:<br>
+ out_file.write(' + %u' % (frame_offset))<br>
+ line_entry = frame.line_entry<br>
+ if line_entry:<br>
+ if options.verbose:<br>
+ # This will output the fullpath + line + column<br>
+ out_file.write(' %s' % (line_entry))<br>
+ else:<br>
+ out_file.write(' %s:%u' % (line_entry.file.basename, line_entry.line))<br>
+ column = line_entry.column<br>
+ if column:<br>
+ out_file.write(':%u' % (column))<br>
+ out_file.write('\n')<br>
+<br>
+ out_file.write('\nBinary Images:\n')<br>
+ for module in target.modules:<br>
+ text_segment = module.section['__TEXT']<br>
+ if text_segment:<br>
+ text_segment_load_addr = text_segment.GetLoadAddress(target)<br>
+ if text_segment_load_addr != lldb.LLDB_INVALID_ADDRESS:<br>
+ text_segment_end_load_addr = text_segment_load_addr + text_segment.size<br>
+ identifier = module.file.basename<br>
+ module_version = '???'<br>
+ module_version_array = module.GetVersion()<br>
+ if module_version_array:<br>
+ module_version = '.'.join(map(str,module_version_array))<br>
+ 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))<br>
+ out_file.close()<br>
+ else:<br>
+ result.PutCString ("error: invalid target");<br>
+<br>
+<br>
+def Symbolicate(debugger, command, result, dict):<br>
+ try:<br>
+ SymbolicateCrashLogs (shlex.split(command))<br>
+ except:<br>
+ result.PutCString ("error: python exception %s" % sys.exc_info()[0])<br>
+<br>
+def SymbolicateCrashLog(crash_log, options):<br>
+ if crash_log.error:<br>
+ print crash_log.error<br>
+ return<br>
+ if options.debug:<br>
+ crash_log.dump()<br>
+ if not crash_log.images:<br>
+ print 'error: no images in crash log'<br>
+ return<br>
+<br>
+ if options.dump_image_list:<br>
+ print "Binary Images:"<br>
+ for image in crash_log.images:<br>
+ if options.verbose:<br>
+ print image.debug_dump()<br>
+ else:<br>
+ print image<br>
+<br>
+ target = crash_log.create_target ()<br>
+ if not target:<br>
+ return<br>
+ exe_module = target.GetModuleAtIndex(0)<br>
+ images_to_load = list()<br>
+ loaded_images = list()<br>
+ if options.load_all_images:<br>
+ # --load-all option was specified, load everything up<br>
+ for image in crash_log.images:<br>
+ images_to_load.append(image)<br>
+ else:<br>
+ # Only load the images found in stack frames for the crashed threads<br>
+ if options.crashed_only:<br>
+ for thread in crash_log.threads:<br>
+ if thread.did_crash():<br>
+ for ident in thread.idents:<br>
+ images = crash_log.find_images_with_identifier (ident)<br>
+ if images:<br>
+ for image in images:<br>
+ images_to_load.append(image)<br>
+ else:<br>
+ print 'error: can\'t find image for identifier "%s"' % ident<br>
+ else:<br>
+ for ident in crash_log.idents:<br>
+ images = crash_log.find_images_with_identifier (ident)<br>
+ if images:<br>
+ for image in images:<br>
+ images_to_load.append(image)<br>
+ else:<br>
+ print 'error: can\'t find image for identifier "%s"' % ident<br>
+<br>
+ for image in images_to_load:<br>
+ if not image in loaded_images:<br>
+ err = image.add_module (target)<br>
+ if err:<br>
+ print err<br>
+ else:<br>
+ #print 'loaded %s' % image<br>
+ loaded_images.append(image)<br>
+<br>
+ if crash_log.backtraces:<br>
+ for thread in crash_log.backtraces:<br>
+ thread.dump_symbolicated (crash_log, options)<br>
+ print<br>
+<br>
+ for thread in crash_log.threads:<br>
+ thread.dump_symbolicated (crash_log, options)<br>
+ print<br>
+<br>
+<br>
+def CreateSymbolicateCrashLogOptions(command_name, description, add_interactive_options):<br>
+ usage = "usage: %prog [options] <FILE> [FILE ...]"<br>
+ option_parser = optparse.OptionParser(description=description, prog='crashlog',usage=usage)<br>
+ option_parser.add_option('--verbose' , '-v', action='store_true', dest='verbose', help='display verbose debug info', default=False)<br>
+ option_parser.add_option('--debug' , '-g', action='store_true', dest='debug', help='display verbose debug logging', default=False)<br>
+ 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)<br>
+ option_parser.add_option('--images' , action='store_true', dest='dump_image_list', help='show image list', default=False)<br>
+ option_parser.add_option('--debug-delay' , type='int', dest='debug_delay', metavar='NSEC', help='pause for NSEC seconds for debugger', default=0)<br>
+ option_parser.add_option('--crashed-only' , '-c', action='store_true', dest='crashed_only', help='only symbolicate the crashed thread', default=False)<br>
+ 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)<br>
+ 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)<br>
+ 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)<br>
+ 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)<br>
+ 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)<br>
+ option_parser.add_option('--source-frames' , type='int', metavar='NFRAMES', dest='source_frames', help='show source for NFRAMES (default = 4)', default=4)<br>
+ 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)<br>
+ if add_interactive_options:<br>
+ option_parser.add_option('-i', '--interactive', action='store_true', help='parse all crash logs and enter interactive mode', default=False)<br>
+ return option_parser<br>
+<br>
+def SymbolicateCrashLogs(command_args):<br>
+ description='''Symbolicate one or more darwin crash log files to provide source file and line information,<br>
+inlined stack frames back to the concrete functions, and disassemble the location of the crash<br>
+for the first frame of the crashed thread.<br>
+If this script is imported into the LLDB command interpreter, a "crashlog" command will be added to the interpreter<br>
+for use at the LLDB command line. After a crash log has been parsed and symbolicated, a target will have been<br>
+created that has all of the shared libraries loaded at the load addresses found in the crash log file. This allows<br>
+you to explore the program as if it were stopped at the locations described in the crash log and functions can<br>
+be disassembled and lookups can be performed using the addresses found in the crash log.'''<br>
+ option_parser = CreateSymbolicateCrashLogOptions ('crashlog', description, True)<br>
+ try:<br>
+ (options, args) = option_parser.parse_args(command_args)<br>
+ except:<br>
+ return<br>
+<br>
+ if options.debug:<br>
+ print 'command_args = %s' % command_args<br>
+ print 'options', options<br>
+ print 'args', args<br>
+<br>
+ if options.debug_delay > 0:<br>
+ print "Waiting %u seconds for debugger to attach..." % options.debug_delay<br>
+ time.sleep(options.debug_delay)<br>
+ error = lldb.SBError()<br>
+<br>
+ if args:<br>
+ if options.interactive:<br>
+ interactive_crashlogs(options, args)<br>
+ else:<br>
+ for crash_log_file in args:<br>
+ crash_log = CrashLog(crash_log_file)<br>
+ SymbolicateCrashLog (crash_log, options)<br>
+if __name__ == '__main__':<br>
+ # Create a new debugger instance<br>
+ lldb.debugger = lldb.SBDebugger.Create()<br>
+ SymbolicateCrashLogs (sys.argv[1:])<br>
+ lldb.SBDebugger.Destroy (lldb.debugger)<br>
+elif getattr(lldb, 'debugger', None):<br>
+ lldb.debugger.HandleCommand('command script add -f lldb.macosx.crashlog.Symbolicate crashlog')<br>
+ lldb.debugger.HandleCommand('command script add -f lldb.macosx.crashlog.save_crashlog save_crashlog')<br>
+ print '"crashlog" and "save_crashlog" command installed, use the "--help" option for detailed help'<br>
+<br>
<br>
Propchange: lldb/trunk/build/Debug/LLDB.framework/Versions/A/Resources/Python/lldb/macosx/crashlog.py<br>
------------------------------------------------------------------------------<br>
svn:executable = *<br>
<br>
Added: lldb/trunk/build/Debug/LLDB.framework/Versions/A/Resources/Python/lldb/macosx/heap.py<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lldb/trunk/build/Debug/LLDB.framework/Versions/A/Resources/Python/lldb/macosx/heap.py?rev=255697&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lldb/trunk/build/Debug/LLDB.framework/Versions/A/Resources/Python/lldb/macosx/heap.py?rev=255697&view=auto</a><br>
==============================================================================<br>
--- lldb/trunk/build/Debug/LLDB.framework/Versions/A/Resources/Python/lldb/macosx/heap.py (added)<br>
+++ lldb/trunk/build/Debug/LLDB.framework/Versions/A/Resources/Python/lldb/macosx/heap.py Tue Dec 15 17:03:22 2015<br>
@@ -0,0 +1,1244 @@<br>
+#!/usr/bin/python<br>
+<br>
+#----------------------------------------------------------------------<br>
+# This module is designed to live inside the "lldb" python package<br>
+# in the "lldb.macosx" package. To use this in the embedded python<br>
+# interpreter using "lldb" just import it:<br>
+#<br>
+# (lldb) script import lldb.macosx.heap<br>
+#----------------------------------------------------------------------<br>
+<br>
+import lldb<br>
+import commands<br>
+import optparse<br>
+import os<br>
+import os.path<br>
+import re<br>
+import shlex<br>
+import string<br>
+import sys<br>
+import tempfile<br>
+import lldb.utils.symbolication<br>
+<br>
+g_libheap_dylib_dir = None<br>
+g_libheap_dylib_dict = dict()<br>
+<br>
+def get_iterate_memory_expr(options, process, user_init_code, user_return_code):<br>
+ expr = '''<br>
+typedef unsigned natural_t;<br>
+typedef uintptr_t vm_size_t;<br>
+typedef uintptr_t vm_address_t;<br>
+typedef natural_t task_t;<br>
+typedef int kern_return_t;<br>
+#define KERN_SUCCESS 0<br>
+typedef void (*range_callback_t)(task_t task, void *baton, unsigned type, uintptr_t ptr_addr, uintptr_t ptr_size);<br>
+''';<br>
+ if options.search_vm_regions:<br>
+ expr += '''<br>
+typedef int vm_prot_t;<br>
+typedef unsigned int vm_inherit_t;<br>
+typedef unsigned long long memory_object_offset_t;<br>
+typedef unsigned int boolean_t;<br>
+typedef int vm_behavior_t;<br>
+typedef uint32_t vm32_object_id_t;<br>
+typedef natural_t mach_msg_type_number_t;<br>
+typedef uint64_t mach_vm_address_t;<br>
+typedef uint64_t mach_vm_offset_t;<br>
+typedef uint64_t mach_vm_size_t;<br>
+typedef uint64_t vm_map_offset_t;<br>
+typedef uint64_t vm_map_address_t;<br>
+typedef uint64_t vm_map_size_t;<br>
+#define VM_PROT_NONE ((vm_prot_t) 0x00)<br>
+#define VM_PROT_READ ((vm_prot_t) 0x01)<br>
+#define VM_PROT_WRITE ((vm_prot_t) 0x02)<br>
+#define VM_PROT_EXECUTE ((vm_prot_t) 0x04)<br>
+typedef struct vm_region_submap_short_info_data_64_t {<br>
+ vm_prot_t protection;<br>
+ vm_prot_t max_protection;<br>
+ vm_inherit_t inheritance;<br>
+ memory_object_offset_t offset; // offset into object/map<br>
+ unsigned int user_tag; // user tag on map entry<br>
+ unsigned int ref_count; // obj/map mappers, etc<br>
+ unsigned short shadow_depth; // only for obj<br>
+ unsigned char external_pager; // only for obj<br>
+ unsigned char share_mode; // see enumeration<br>
+ boolean_t is_submap; // submap vs obj<br>
+ vm_behavior_t behavior; // access behavior hint<br>
+ vm32_object_id_t object_id; // obj/map name, not a handle<br>
+ unsigned short user_wired_count;<br>
+} vm_region_submap_short_info_data_64_t;<br>
+#define VM_REGION_SUBMAP_SHORT_INFO_COUNT_64 ((mach_msg_type_number_t)(sizeof(vm_region_submap_short_info_data_64_t)/sizeof(int)))''';<br>
+ if user_init_code:<br>
+ expr += user_init_code;<br>
+ expr += '''<br>
+task_t task = (task_t)mach_task_self();<br>
+mach_vm_address_t vm_region_base_addr;<br>
+mach_vm_size_t vm_region_size;<br>
+natural_t vm_region_depth;<br>
+vm_region_submap_short_info_data_64_t vm_region_info;<br>
+kern_return_t err;<br>
+for (vm_region_base_addr = 0, vm_region_size = 1; vm_region_size != 0; vm_region_base_addr += vm_region_size)<br>
+{<br>
+ mach_msg_type_number_t vm_region_info_size = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64;<br>
+ err = (kern_return_t)mach_vm_region_recurse (task,<br>
+ &vm_region_base_addr,<br>
+ &vm_region_size,<br>
+ &vm_region_depth,<br>
+ &vm_region_info,<br>
+ &vm_region_info_size);<br>
+ if (err)<br>
+ break;<br>
+ // Check all read + write regions. This will cover the thread stacks<br>
+ // and any regions of memory like __DATA segments, that might contain<br>
+ // data we are looking for<br>
+ if (vm_region_info.protection & VM_PROT_WRITE &&<br>
+ vm_region_info.protection & VM_PROT_READ)<br>
+ {<br>
+ baton.callback (task,<br>
+ &baton,<br>
+ 64,<br>
+ vm_region_base_addr,<br>
+ vm_region_size);<br>
+ }<br>
+}'''<br>
+ else:<br>
+ if options.search_stack:<br>
+ expr += get_thread_stack_ranges_struct (process)<br>
+ if options.search_segments:<br>
+ expr += get_sections_ranges_struct (process)<br>
+ if user_init_code:<br>
+ expr += user_init_code<br>
+ if options.search_heap:<br>
+ expr += '''<br>
+#define MALLOC_PTR_IN_USE_RANGE_TYPE 1<br>
+typedef struct vm_range_t {<br>
+ vm_address_t address;<br>
+ vm_size_t size;<br>
+} vm_range_t;<br>
+typedef kern_return_t (*memory_reader_t)(task_t task, vm_address_t remote_address, vm_size_t size, void **local_memory);<br>
+typedef void (*vm_range_recorder_t)(task_t task, void *baton, unsigned type, vm_range_t *range, unsigned size);<br>
+typedef struct malloc_introspection_t {<br>
+ kern_return_t (*enumerator)(task_t task, void *, unsigned type_mask, vm_address_t zone_address, memory_reader_t reader, vm_range_recorder_t recorder); /* enumerates all the malloc pointers in use */<br>
+} malloc_introspection_t;<br>
+typedef struct malloc_zone_t {<br>
+ void *reserved1[12];<br>
+ struct malloc_introspection_t *introspect;<br>
+} malloc_zone_t;<br>
+memory_reader_t task_peek = [](task_t task, vm_address_t remote_address, vm_size_t size, void **local_memory) -> kern_return_t {<br>
+ *local_memory = (void*) remote_address;<br>
+ return KERN_SUCCESS;<br>
+};<br>
+vm_address_t *zones = 0;<br>
+unsigned int num_zones = 0;task_t task = 0;<br>
+kern_return_t err = (kern_return_t)malloc_get_all_zones (task, task_peek, &zones, &num_zones);<br>
+if (KERN_SUCCESS == err)<br>
+{<br>
+ for (unsigned int i=0; i<num_zones; ++i)<br>
+ {<br>
+ const malloc_zone_t *zone = (const malloc_zone_t *)zones[i];<br>
+ if (zone && zone->introspect)<br>
+ zone->introspect->enumerator (task,<br>
+ &baton,<br>
+ MALLOC_PTR_IN_USE_RANGE_TYPE,<br>
+ (vm_address_t)zone,<br>
+ task_peek,<br>
+ [] (task_t task, void *baton, unsigned type, vm_range_t *ranges, unsigned size) -> void<br>
+ {<br>
+ range_callback_t callback = ((callback_baton_t *)baton)->callback;<br>
+ for (unsigned i=0; i<size; ++i)<br>
+ {<br>
+ callback (task, baton, type, ranges[i].address, ranges[i].size);<br>
+ }<br>
+ });<br>
+ }<br>
+}'''<br>
+<br>
+ if options.search_stack:<br>
+ expr += '''<br>
+#ifdef NUM_STACKS<br>
+// Call the callback for the thread stack ranges<br>
+for (uint32_t i=0; i<NUM_STACKS; ++i) {<br>
+ range_callback(task, &baton, 8, stacks[i].base, stacks[i].size);<br>
+ if (STACK_RED_ZONE_SIZE > 0) {<br>
+ range_callback(task, &baton, 16, stacks[i].base - STACK_RED_ZONE_SIZE, STACK_RED_ZONE_SIZE);<br>
+ }<br>
+}<br>
+#endif'''<br>
+<br>
+ if options.search_segments:<br>
+ expr += '''<br>
+#ifdef NUM_SEGMENTS<br>
+// Call the callback for all segments<br>
+for (uint32_t i=0; i<NUM_SEGMENTS; ++i)<br>
+ range_callback(task, &baton, 32, segments[i].base, segments[i].size);<br>
+#endif'''<br>
+<br>
+ if user_return_code:<br>
+ expr += "\n%s" % (user_return_code,)<br>
+<br>
+ return expr<br>
+<br>
+def get_member_types_for_offset(value_type, offset, member_list):<br>
+ member = value_type.GetFieldAtIndex(0)<br>
+ search_bases = False<br>
+ if member:<br>
+ if member.GetOffsetInBytes() <= offset:<br>
+ for field_idx in range (value_type.GetNumberOfFields()):<br>
+ member = value_type.GetFieldAtIndex(field_idx)<br>
+ member_byte_offset = member.GetOffsetInBytes()<br>
+ member_end_byte_offset = member_byte_offset + member.type.size<br>
+ if member_byte_offset <= offset and offset < member_end_byte_offset:<br>
+ member_list.append(member)<br>
+ get_member_types_for_offset (member.type, offset - member_byte_offset, member_list)<br>
+ return<br>
+ else:<br>
+ search_bases = True<br>
+ else:<br>
+ search_bases = True<br>
+ if search_bases:<br>
+ for field_idx in range (value_type.GetNumberOfDirectBaseClasses()):<br>
+ member = value_type.GetDirectBaseClassAtIndex(field_idx)<br>
+ member_byte_offset = member.GetOffsetInBytes()<br>
+ member_end_byte_offset = member_byte_offset + member.type.size<br>
+ if member_byte_offset <= offset and offset < member_end_byte_offset:<br>
+ member_list.append(member)<br>
+ get_member_types_for_offset (member.type, offset - member_byte_offset, member_list)<br>
+ return<br>
+ for field_idx in range (value_type.GetNumberOfVirtualBaseClasses()):<br>
+ member = value_type.GetVirtualBaseClassAtIndex(field_idx)<br>
+ member_byte_offset = member.GetOffsetInBytes()<br>
+ member_end_byte_offset = member_byte_offset + member.type.size<br>
+ if member_byte_offset <= offset and offset < member_end_byte_offset:<br>
+ member_list.append(member)<br>
+ get_member_types_for_offset (member.type, offset - member_byte_offset, member_list)<br>
+ return<br>
+<br>
+def append_regex_callback(option, opt, value, parser):<br>
+ try:<br>
+ ivar_regex = re.compile(value)<br>
+ parser.values.ivar_regex_blacklist.append(ivar_regex)<br>
+ except:<br>
+ print 'error: an exception was thrown when compiling the ivar regular expression for "%s"' % value<br>
+<br>
+def add_common_options(parser):<br>
+ parser.add_option('-v', '--verbose', action='store_true', dest='verbose', help='display verbose debug info', default=False)<br>
+ parser.add_option('-t', '--type', action='store_true', dest='print_type', help='print the full value of the type for each matching malloc block', default=False)<br>
+ parser.add_option('-o', '--po', action='store_true', dest='print_object_description', help='print the object descriptions for any matches', default=False)<br>
+ parser.add_option('-z', '--size', action='store_true', dest='show_size', help='print the allocation size in bytes', default=False)<br>
+ parser.add_option('-r', '--range', action='store_true', dest='show_range', help='print the allocation address range instead of just the allocation base address', default=False)<br>
+ parser.add_option('-m', '--memory', action='store_true', dest='memory', help='dump the memory for each matching block', default=False)<br>
+ parser.add_option('-f', '--format', type='string', dest='format', help='the format to use when dumping memory if --memory is specified', default=None)<br>
+ parser.add_option('-I', '--omit-ivar-regex', type='string', action='callback', callback=append_regex_callback, dest='ivar_regex_blacklist', default=[], help='specify one or more regular expressions used to backlist any matches that are in ivars')<br>
+ parser.add_option('-s', '--stack', action='store_true', dest='stack', help='gets the stack that allocated each malloc block if MallocStackLogging is enabled', default=False)<br>
+ parser.add_option('-S', '--stack-history', action='store_true', dest='stack_history', help='gets the stack history for all allocations whose start address matches each malloc block if MallocStackLogging is enabled', default=False)<br>
+ parser.add_option('-F', '--max-frames', type='int', dest='max_frames', help='the maximum number of stack frames to print when using the --stack or --stack-history options (default=128)', default=128)<br>
+ parser.add_option('-H', '--max-history', type='int', dest='max_history', help='the maximum number of stack history backtraces to print for each allocation when using the --stack-history option (default=16)', default=16)<br>
+ parser.add_option('-M', '--max-matches', type='int', dest='max_matches', help='the maximum number of matches to print', default=32)<br>
+ parser.add_option('-O', '--offset', type='int', dest='offset', help='the matching data must be at this offset', default=-1)<br>
+ parser.add_option('--ignore-stack', action='store_false', dest='search_stack', help="Don't search the stack when enumerating memory", default=True)<br>
+ parser.add_option('--ignore-heap', action='store_false', dest='search_heap', help="Don't search the heap allocations when enumerating memory", default=True)<br>
+ parser.add_option('--ignore-segments', action='store_false', dest='search_segments', help="Don't search readable executable segments enumerating memory", default=True)<br>
+ parser.add_option('-V', '--vm-regions', action='store_true', dest='search_vm_regions', help='Check all VM regions instead of searching the heap, stack and segments', default=False)<br>
+<br>
+def type_flags_to_string(type_flags):<br>
+ if type_flags == 0:<br>
+ type_str = 'free'<br>
+ elif type_flags & 2:<br>
+ type_str = 'malloc'<br>
+ elif type_flags & 4:<br>
+ type_str = 'free'<br>
+ elif type_flags & 1:<br>
+ type_str = 'generic'<br>
+ elif type_flags & 8:<br>
+ type_str = 'stack'<br>
+ elif type_flags & 16:<br>
+ type_str = 'stack (red zone)'<br>
+ elif type_flags & 32:<br>
+ type_str = 'segment'<br>
+ elif type_flags & 64:<br>
+ type_str = 'vm_region'<br>
+ else:<br>
+ type_str = hex(type_flags)<br>
+ return type_str<br>
+<br>
+def find_variable_containing_address(verbose, frame, match_addr):<br>
+ variables = frame.GetVariables(True,True,True,True)<br>
+ matching_var = None<br>
+ for var in variables:<br>
+ var_addr = var.GetLoadAddress()<br>
+ if var_addr != lldb.LLDB_INVALID_ADDRESS:<br>
+ byte_size = var.GetType().GetByteSize()<br>
+ if verbose:<br>
+ print 'frame #%u: [%#x - %#x) %s' % (frame.GetFrameID(), var.load_addr, var.load_addr + byte_size, <a href="http://var.name" rel="noreferrer" target="_blank">var.name</a>)<br>
+ if var_addr == match_addr:<br>
+ if verbose:<br>
+ print 'match'<br>
+ return var<br>
+ else:<br>
+ if byte_size > 0 and var_addr <= match_addr and match_addr < (var_addr + byte_size):<br>
+ if verbose:<br>
+ print 'match'<br>
+ return var<br>
+ return None<br>
+<br>
+def find_frame_for_stack_address(process, addr):<br>
+ closest_delta = sys.maxint<br>
+ closest_frame = None<br>
+ #print 'find_frame_for_stack_address(%#x)' % (addr)<br>
+ for thread in process:<br>
+ prev_sp = lldb.LLDB_INVALID_ADDRESS<br>
+ for frame in thread:<br>
+ cfa = frame.GetCFA()<br>
+ #print 'frame #%u: cfa = %#x' % (frame.GetFrameID(), cfa)<br>
+ if addr < cfa:<br>
+ delta = cfa - addr<br>
+ #print '%#x < %#x, delta = %</blockquote></div>