<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>