[Lldb-commits] [lldb] r255697 - First pass at LLDBRPC.framework

Greg Clayton via lldb-commits lldb-commits at lists.llvm.org
Tue Dec 15 15:10:42 PST 2015


Xcode checked stuff in incorrectly from another project that contained the LLDB.framework that I built. I will be removing ASAP.


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



More information about the lldb-commits mailing list