[Lldb-commits] [lldb] r156201 - in /lldb/trunk/examples/python: crashlog.py symbolication.py

Greg Clayton gclayton at apple.com
Fri May 4 13:44:14 PDT 2012


Author: gclayton
Date: Fri May  4 15:44:14 2012
New Revision: 156201

URL: http://llvm.org/viewvc/llvm-project?rev=156201&view=rev
Log:
Added an interactive mode to the "crashlog" command so that we can look at multiple crash logs at once and do some data mining. Added an interactive command prompt that allows you to do:

% PYTHONPATH=./build/Debug/LLDB.framework/Resources/Python ; ./build/Debug//LLDB.framework/Resources/Python/lldb/macosx/crashlog.py -i ~/Downloads/crashes2/*.crash ) 

then you get an interactive prompt where you can search for data within all crash logs. For example you can do:

% list

which will list all crash logs

And you can search for all images given an image basename, or full path:

% image LLDB
% image /Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Versions/A/LLDB
% image LLDB.framework

Which would all produce an output listing like:

40CD4430-7D27-3248-BE4C-71B1F36FC5D0 (1.132 - 132) /Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Versions/A/LLDB, __TEXT=[0x000000011f8bc000 - 0x0000000120d3efbf)
B727A528-FF1F-3B20-9E4F-BBE96C7D922D (1.136 - 136) /Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Versions/A/LLDB, __TEXT=[0x000000011e7f7000 - 0x000000011fc7ff87)
4D6F8DC2-5757-39C7-96B0-1A5B5171DC6B (1.137 - 137) /Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Versions/A/LLDB, __TEXT=[0x000000012bd7f000 - 0x000000012d1fcfef)
FBF8786F-92B9-31E3-8BCD-A82148338966 (1.137 - 137) /Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Versions/A/LLDB, __TEXT=[0x0000000122d78000 - 0x00000001241f5fd7)
7AE082E3-3BB7-3F64-A308-063E559DFC45 (1.143 - 143) /Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Versions/A/LLDB, __TEXT=[0x0000000119b8d000 - 0x000000011b02ef5f)
7AE082E3-3BB7-3F64-A308-063E559DFC45 (1.143 - 143) /Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Versions/A/LLDB, __TEXT=[0x0000000111497000 - 0x0000000112938f5f)
7AE082E3-3BB7-3F64-A308-063E559DFC45 (1.143 - 143) /Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Versions/A/LLDB, __TEXT=[0x0000000116680000 - 0x0000000117b21f5f)




Modified:
    lldb/trunk/examples/python/crashlog.py
    lldb/trunk/examples/python/symbolication.py

Modified: lldb/trunk/examples/python/crashlog.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/examples/python/crashlog.py?rev=156201&r1=156200&r2=156201&view=diff
==============================================================================
--- lldb/trunk/examples/python/crashlog.py (original)
+++ lldb/trunk/examples/python/crashlog.py Fri May  4 15:44:14 2012
@@ -28,16 +28,19 @@
 
 import lldb
 import commands
+import cmd
+import glob
 import optparse
 import os
 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
-import lldb.utils.symbolication 
+from lldb.utils import symbolication
 
 PARSE_MODE_NORMAL = 0
 PARSE_MODE_THREAD = 1
@@ -45,7 +48,7 @@
 PARSE_MODE_THREGS = 3
 PARSE_MODE_SYSTEM = 4
 
-class CrashLog(lldb.utils.symbolication.Symbolicator):
+class CrashLog(symbolication.Symbolicator):
     """Class that does parses darwin crash logs"""
     thread_state_regex = re.compile('^Thread ([0-9]+) crashed with')
     thread_regex = re.compile('^Thread ([0-9]+)([^:]*):(.*)')
@@ -100,7 +103,7 @@
         def dump(self, prefix):
             print "%s%s" % (prefix, str(self))
     
-    class DarwinImage(lldb.utils.symbolication.Image):
+    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):
@@ -109,8 +112,8 @@
         dwarfdump_uuid_regex = re.compile('UUID: ([-0-9a-fA-F]+) \(([^\(]+)\) .*')
         
         def __init__(self, text_addr_lo, text_addr_hi, identifier, version, uuid, path):
-            lldb.utils.symbolication.Image.__init__(self, path, uuid);
-            self.add_section (lldb.utils.symbolication.Section(text_addr_lo, text_addr_hi, "__TEXT"))
+            symbolication.Image.__init__(self, path, uuid);
+            self.add_section (symbolication.Section(text_addr_lo, text_addr_hi, "__TEXT"))
             self.identifier = identifier
             self.version = version
         
@@ -161,7 +164,7 @@
         
     def __init__(self, path):
         """CrashLog constructor that take a path to a darwin crash log file"""
-        lldb.utils.symbolication.Symbolicator.__init__(self);
+        symbolication.Symbolicator.__init__(self);
         self.path = os.path.expanduser(path);
         self.info_lines = list()
         self.system_profile = list()
@@ -316,7 +319,7 @@
     
     def create_target(self):
         #print 'crashlog.create_target()...'
-        target = lldb.utils.symbolication.Symbolicator.create_target(self)
+        target = symbolication.Symbolicator.create_target(self)
         if target:
             return target
         # We weren't able to open the main executable as, but we can still symbolicate
@@ -342,6 +345,101 @@
     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.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_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 an image in the crash log given an image basename.
+        
+        USAGE: image <basename>'''
+        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 or a image basename.'''
+        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
+        
+        for image_path in args:
+            fullpath_search = image_path[0] == '/'
+            for crash_log in 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 image
+                    else:
+                        image_basename = image.get_resolved_path_basename()
+                        if image_basename == image_path:
+                            matches_found += 1
+                            print image
+                if matches_found == 0:
+                    for (image_idx, image) in enumerate(crash_log.images):
+                        if string.find(image.get_resolved_path(), image_path) >= 0:
+                            print 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.verbose:
+            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 Symbolicate(debugger, command, result, dict):
     try:
         SymbolicateCrashLog (shlex.split(command))
@@ -358,19 +456,17 @@
 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.'''
-    parser = optparse.OptionParser(description=description, prog='crashlog.py',usage=usage)
-    parser.add_option('--platform', type='string', metavar='platform', dest='platform', help='specify one platform by name')
+    parser = optparse.OptionParser(description=description, prog='crashlog',usage=usage)
     parser.add_option('-v', '--verbose', action='store_true', dest='verbose', help='display verbose debug info', default=False)
-    parser.add_option('--no-images', action='store_false', dest='show_images', help='don\'t show images in stack frames', default=True)
     parser.add_option('-a', '--load-all', action='store_true', dest='load_all_images', help='load all executable images, not just the images found in the crashed stack frames', default=False)
-    parser.add_option('--image-list', action='store_true', dest='dump_image_list', help='show image list', default=False)
+    parser.add_option('--images', action='store_true', dest='dump_image_list', help='show image list', default=False)
     parser.add_option('-g', '--debug-delay', type='int', dest='debug_delay', metavar='NSEC', help='pause for NSEC seconds for debugger', default=0)
     parser.add_option('-c', '--crashed-only', action='store_true', dest='crashed_only', help='only symbolicate the crashed thread', default=False)
     parser.add_option('-d', '--disasm-depth', type='int', dest='disassemble_depth', help='set the depth in stack frames that should be disassembled (default is 1)', default=1)
     parser.add_option('-D', '--disasm-all', action='store_true', dest='disassemble_all_threads', help='enabled disassembly of frames on all threads (not just the crashed thread)', default=False)
     parser.add_option('-B', '--disasm-before', type='int', dest='disassemble_before', help='the number of instructions to disassemble before the frame PC', default=4)
     parser.add_option('-A', '--disasm-after', type='int', dest='disassemble_after', help='the number of instructions to disassemble after the frame PC', default=4)
-    loaded_addresses = False
+    parser.add_option('-i', '--interactive', action='store_true', help='parse all crash logs and enter interactive mode', default=False)
     try:
         (options, args) = parser.parse_args(command_args)
     except:
@@ -385,85 +481,89 @@
         print "Waiting %u seconds for debugger to attach..." % options.debug_delay
         time.sleep(options.debug_delay)
     error = lldb.SBError()
+        
     if args:
-        for crash_log_file in args:
-            crash_log = CrashLog(crash_log_file)
-            
-            #pp = pprint.PrettyPrinter(indent=4); pp.pprint(args)
-            if crash_log.error:
-                print crash_log.error
-                return
-            if options.verbose:
-                crash_log.dump()
-            if not crash_log.images:
-                print 'error: no images in crash log'
-                return
-
-            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
-                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
+        if options.interactive:
+            interactive_crashlogs(options, args)
+        else:
+            for crash_log_file in args:
+                crash_log = CrashLog(crash_log_file)
             
-            for image in images_to_load:
-                if image in loaded_images:
-                    print "warning: skipping %s loaded at %#16.16x duplicate entry (probably commpage)" % (image.path, image.text_addr_lo)
+                #pp = pprint.PrettyPrinter(indent=4); pp.pprint(args)
+                if crash_log.error:
+                    print crash_log.error
+                    return
+                if options.verbose:
+                    crash_log.dump()
+                if not crash_log.images:
+                    print 'error: no images in crash log'
+                    return
+
+                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:
-                    err = image.add_module (target)
-                    if err:
-                        print err
+                    # Only load the images found in stack frames for the crashed threads
+                    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 image in loaded_images:
+                        print "warning: skipping %s loaded at %#16.16x duplicate entry (probably commpage)" % (image.path, image.text_addr_lo)
                     else:
-                        #print 'loaded %s' % image
-                        loaded_images.append(image)
+                        err = image.add_module (target)
+                        if err:
+                            print err
+                        else:
+                            #print 'loaded %s' % image
+                            loaded_images.append(image)
             
-            for thread in crash_log.threads:
-                this_thread_crashed = thread.did_crash()
-                if options.crashed_only and this_thread_crashed == False:
-                    continue
-                print "%s" % thread
-                #prev_frame_index = -1
-                for frame_idx, frame in enumerate(thread.frames):
-                    disassemble = (this_thread_crashed or options.disassemble_all_threads) and frame_idx < options.disassemble_depth;
-                    symbolicated_frame_addresses = crash_log.symbolicate (frame.pc)
-                    if symbolicated_frame_addresses:
-                        symbolicated_frame_address_idx = 0
-                        for symbolicated_frame_address in symbolicated_frame_addresses:
-                            print '[%3u] %s' % (frame_idx, symbolicated_frame_address)
+                for thread in crash_log.threads:
+                    this_thread_crashed = thread.did_crash()
+                    if options.crashed_only and this_thread_crashed == False:
+                        continue
+                    print "%s" % thread
+                    #prev_frame_index = -1
+                    for frame_idx, frame in enumerate(thread.frames):
+                        disassemble = (this_thread_crashed or options.disassemble_all_threads) and frame_idx < options.disassemble_depth;
+                        symbolicated_frame_addresses = crash_log.symbolicate (frame.pc)
+                        if symbolicated_frame_addresses:
+                            symbolicated_frame_address_idx = 0
+                            for symbolicated_frame_address in symbolicated_frame_addresses:
+                                print '[%3u] %s' % (frame_idx, symbolicated_frame_address)
                             
-                            if symbolicated_frame_address_idx == 0:
-                                if disassemble:
-                                    instructions = symbolicated_frame_address.get_instructions()
-                                    if instructions:
-                                        print
-                                        lldb.utils.symbolication.disassemble_instructions (target, 
-                                                                                           instructions, 
-                                                                                           frame.pc, 
-                                                                                           options.disassemble_before, 
-                                                                                           options.disassemble_after, frame.index > 0)
-                                        print
-                            symbolicated_frame_address_idx += 1
-                    else:
-                        print frame
-                print                
-
-            if options.dump_image_list:
-                print "Binary Images:"
-                for image in crash_log.images:
-                    print image
+                                if symbolicated_frame_address_idx == 0:
+                                    if disassemble:
+                                        instructions = symbolicated_frame_address.get_instructions()
+                                        if instructions:
+                                            print
+                                            symbolication.disassemble_instructions (target, 
+                                                                                    instructions, 
+                                                                                    frame.pc, 
+                                                                                    options.disassemble_before, 
+                                                                                    options.disassemble_after, frame.index > 0)
+                                            print
+                                symbolicated_frame_address_idx += 1
+                        else:
+                            print frame
+                    print                
+
+                if options.dump_image_list:
+                    print "Binary Images:"
+                    for image in crash_log.images:
+                        print image
 
 if __name__ == '__main__':
     # Create a new debugger instance

Modified: lldb/trunk/examples/python/symbolication.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/examples/python/symbolication.py?rev=156201&r1=156200&r2=156201&view=diff
==============================================================================
--- lldb/trunk/examples/python/symbolication.py (original)
+++ lldb/trunk/examples/python/symbolication.py Fri May  4 15:44:14 2012
@@ -206,7 +206,7 @@
         print "%s%s" % (prefix, self)
     
     def __str__(self):
-        s = "%s %s" % (self.get_uuid(), self.get_resolved_path())
+        s = "%s %s %s" % (self.get_uuid(), self.version, self.get_resolved_path())
         for section_info in self.section_infos:
             s += ", %s" % (section_info)
         if self.slide != None:





More information about the lldb-commits mailing list