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 <ztur...@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@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 = % _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits