Greg Clayton | fed5267 | 2012-03-22 23:08:07 +0000 | [diff] [blame^] | 1 | #!/usr/bin/python |
| 2 | |
| 3 | #---------------------------------------------------------------------- |
| 4 | # This module will enable GDB remote packet logging when the |
| 5 | # 'start_gdb_log' command is called with a filename to log to. When the |
| 6 | # 'stop_gdb_log' command is called, it will disable the logging and |
| 7 | # print out statistics about how long commands took to execute and also |
| 8 | # will primnt ou |
| 9 | # Be sure to add the python path that points to the LLDB shared library. |
| 10 | # |
| 11 | # To use this in the embedded python interpreter using "lldb" just |
| 12 | # import it with the full path using the "command script import" |
| 13 | # command. This can be done from the LLDB command line: |
| 14 | # (lldb) command script import /path/to/gdbremote.py |
| 15 | # Or it can be added to your ~/.lldbinit file so this module is always |
| 16 | # available. |
| 17 | #---------------------------------------------------------------------- |
| 18 | |
| 19 | import commands |
| 20 | import optparse |
| 21 | import os |
| 22 | import shlex |
| 23 | import re |
| 24 | import tempfile |
| 25 | |
| 26 | def start_gdb_log(debugger, command, result, dict): |
| 27 | '''Start logging GDB remote packets by enabling logging with timestamps and |
| 28 | thread safe logging. Follow a call to this function with a call to "stop_gdb_log" |
| 29 | in order to dump out the commands.''' |
| 30 | global log_file |
| 31 | if log_file: |
| 32 | result.PutCString ('error: logging is already in progress with file "%s"', log_file) |
| 33 | else: |
| 34 | args_len = len(args) |
| 35 | if args_len == 0: |
| 36 | log_file = tempfile.mktemp() |
| 37 | elif len(args) == 1: |
| 38 | log_file = args[0] |
| 39 | |
| 40 | if log_file: |
| 41 | debugger.HandleCommand('log enable --threadsafe --timestamp --file "%s" gdb-remote packets' % log_file); |
| 42 | result.PutCString ("GDB packet logging enable with log file '%s'\nUse the 'stop_gdb_log' command to stop logging and show packet statistics." % log_file) |
| 43 | return |
| 44 | |
| 45 | result.PutCString ('error: invalid log file path') |
| 46 | result.PutCString (usage) |
| 47 | |
| 48 | def parse_time_log(debugger, command, result, dict): |
| 49 | # Any commands whose names might be followed by more valid C identifier |
| 50 | # characters must be listed here |
| 51 | command_args = shlex.split(command) |
| 52 | usage = "usage: parse_time_log [options] [<LOGFILEPATH>]" |
| 53 | description='''Parse a log file that contains timestamps and convert the timestamps to delta times between log lines.''' |
| 54 | parser = optparse.OptionParser(description=description, prog='parse_time_log',usage=usage) |
| 55 | parser.add_option('-v', '--verbose', action='store_true', dest='verbose', help='display verbose debug info', default=False) |
| 56 | try: |
| 57 | (options, args) = parser.parse_args(command_args) |
| 58 | except: |
| 59 | return |
| 60 | for log_file in args: |
| 61 | parse_log_file (log_file, options) |
| 62 | |
| 63 | def parse_log_file(file, options): |
| 64 | '''Parse a log file that was contains timestamps. These logs are typically |
| 65 | generated using: |
| 66 | (lldb) log enable --threadsafe --timestamp --file <FILE> .... |
| 67 | |
| 68 | This log file will contain timestamps and this fucntion will then normalize |
| 69 | those packets to be relative to the first value timestamp that is found and |
| 70 | show delta times between log lines and also keep track of how long it takes |
| 71 | for GDB remote commands to make a send/receive round trip. This can be |
| 72 | handy when trying to figure out why some operation in the debugger is taking |
| 73 | a long time during a preset set of debugger commands.''' |
| 74 | |
| 75 | timestamp_regex = re.compile('(\s*)([1-9][0-9]+\.[0-9]+)([^0-9].*)$') |
| 76 | |
| 77 | base_time = 0.0 |
| 78 | last_time = 0.0 |
| 79 | file = open(file) |
| 80 | lines = file.read().splitlines() |
| 81 | for line in lines: |
| 82 | match = timestamp_regex.match (line) |
| 83 | if match: |
| 84 | curr_time = float (match.group(2)) |
| 85 | delta = 0.0 |
| 86 | if base_time: |
| 87 | delta = curr_time - last_time |
| 88 | else: |
| 89 | base_time = curr_time |
| 90 | |
| 91 | print '%s%.6f %+.6f%s' % (match.group(1), curr_time - base_time, delta, match.group(3)) |
| 92 | last_time = curr_time |
| 93 | else: |
| 94 | print line |
| 95 | |
| 96 | |
| 97 | |
| 98 | if __name__ == '__main__': |
| 99 | import sys |
| 100 | # This script is being run from the command line, create a debugger in case we are |
| 101 | # going to use any debugger functions in our function. |
| 102 | for file in sys.argv: |
| 103 | print '#----------------------------------------------------------------------' |
| 104 | print "# Log file: '%s'" % file |
| 105 | print '#----------------------------------------------------------------------' |
| 106 | parse_log_file (file, None) |
| 107 | |
| 108 | else: |
| 109 | import lldb |
| 110 | if lldb.debugger: |
| 111 | # This initializer is being run from LLDB in the embedded command interpreter |
| 112 | # Add any commands contained in this module to LLDB |
| 113 | lldb.debugger.HandleCommand('command script add -f delta.parse_time_log parse_time_log') |
| 114 | print 'The "parse_time_log" command is now installed and ready for use, type "parse_time_log --help" for more information' |