xref: /openbsd-src/gnu/llvm/lldb/examples/python/delta.py (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1be691f3bSpatrick#!/usr/bin/env python
2061da546Spatrick
3061da546Spatrick#----------------------------------------------------------------------
4061da546Spatrick# This module will enable GDB remote packet logging when the
5061da546Spatrick# 'start_gdb_log' command is called with a filename to log to. When the
6061da546Spatrick# 'stop_gdb_log' command is called, it will disable the logging and
7061da546Spatrick# print out statistics about how long commands took to execute and also
8061da546Spatrick# will primnt ou
9061da546Spatrick# Be sure to add the python path that points to the LLDB shared library.
10061da546Spatrick#
11061da546Spatrick# To use this in the embedded python interpreter using "lldb" just
12061da546Spatrick# import it with the full path using the "command script import"
13061da546Spatrick# command. This can be done from the LLDB command line:
14061da546Spatrick#   (lldb) command script import /path/to/gdbremote.py
15061da546Spatrick# Or it can be added to your ~/.lldbinit file so this module is always
16061da546Spatrick# available.
17061da546Spatrick#----------------------------------------------------------------------
18061da546Spatrick
19061da546Spatrickimport optparse
20061da546Spatrickimport os
21061da546Spatrickimport shlex
22061da546Spatrickimport re
23061da546Spatrickimport tempfile
24061da546Spatrick
25061da546Spatrick
26061da546Spatrickdef start_gdb_log(debugger, command, result, dict):
27061da546Spatrick    '''Start logging GDB remote packets by enabling logging with timestamps and
28061da546Spatrick    thread safe logging. Follow a call to this function with a call to "stop_gdb_log"
29061da546Spatrick    in order to dump out the commands.'''
30061da546Spatrick    global log_file
31061da546Spatrick    if log_file:
32061da546Spatrick        result.PutCString(
33061da546Spatrick            'error: logging is already in progress with file "%s"',
34061da546Spatrick            log_file)
35061da546Spatrick    else:
36061da546Spatrick        args_len = len(args)
37061da546Spatrick        if args_len == 0:
38061da546Spatrick            log_file = tempfile.mktemp()
39061da546Spatrick        elif len(args) == 1:
40061da546Spatrick            log_file = args[0]
41061da546Spatrick
42061da546Spatrick        if log_file:
43061da546Spatrick            debugger.HandleCommand(
44061da546Spatrick                'log enable --threadsafe --timestamp --file "%s" gdb-remote packets' %
45061da546Spatrick                log_file)
46061da546Spatrick            result.PutCString(
47061da546Spatrick                "GDB packet logging enable with log file '%s'\nUse the 'stop_gdb_log' command to stop logging and show packet statistics." %
48061da546Spatrick                log_file)
49061da546Spatrick            return
50061da546Spatrick
51061da546Spatrick        result.PutCString('error: invalid log file path')
52061da546Spatrick    result.PutCString(usage)
53061da546Spatrick
54061da546Spatrick
55061da546Spatrickdef parse_time_log(debugger, command, result, dict):
56061da546Spatrick    # Any commands whose names might be followed by more valid C identifier
57061da546Spatrick    # characters must be listed here
58061da546Spatrick    command_args = shlex.split(command)
59061da546Spatrick    parse_time_log_args(command_args)
60061da546Spatrick
61061da546Spatrick
62061da546Spatrickdef parse_time_log_args(command_args):
63061da546Spatrick    usage = "usage: parse_time_log [options] [<LOGFILEPATH>]"
64061da546Spatrick    description = '''Parse a log file that contains timestamps and convert the timestamps to delta times between log lines.'''
65061da546Spatrick    parser = optparse.OptionParser(
66061da546Spatrick        description=description,
67061da546Spatrick        prog='parse_time_log',
68061da546Spatrick        usage=usage)
69061da546Spatrick    parser.add_option(
70061da546Spatrick        '-v',
71061da546Spatrick        '--verbose',
72061da546Spatrick        action='store_true',
73061da546Spatrick        dest='verbose',
74061da546Spatrick        help='display verbose debug info',
75061da546Spatrick        default=False)
76061da546Spatrick    try:
77061da546Spatrick        (options, args) = parser.parse_args(command_args)
78061da546Spatrick    except:
79061da546Spatrick        return
80061da546Spatrick    for log_file in args:
81061da546Spatrick        parse_log_file(log_file, options)
82061da546Spatrick
83061da546Spatrick
84061da546Spatrickdef parse_log_file(file, options):
85061da546Spatrick    '''Parse a log file that was contains timestamps. These logs are typically
86061da546Spatrick    generated using:
87061da546Spatrick    (lldb) log enable --threadsafe --timestamp --file <FILE> ....
88061da546Spatrick
89061da546Spatrick    This log file will contain timestamps and this function will then normalize
90061da546Spatrick    those packets to be relative to the first value timestamp that is found and
91061da546Spatrick    show delta times between log lines and also keep track of how long it takes
92061da546Spatrick    for GDB remote commands to make a send/receive round trip. This can be
93061da546Spatrick    handy when trying to figure out why some operation in the debugger is taking
94061da546Spatrick    a long time during a preset set of debugger commands.'''
95061da546Spatrick
96061da546Spatrick    print('#----------------------------------------------------------------------')
97061da546Spatrick    print("# Log file: '%s'" % file)
98061da546Spatrick    print('#----------------------------------------------------------------------')
99061da546Spatrick
100061da546Spatrick    timestamp_regex = re.compile('(\s*)([1-9][0-9]+\.[0-9]+)([^0-9].*)$')
101061da546Spatrick
102061da546Spatrick    base_time = 0.0
103061da546Spatrick    last_time = 0.0
104061da546Spatrick    file = open(file)
105061da546Spatrick    lines = file.read().splitlines()
106061da546Spatrick    for line in lines:
107061da546Spatrick        match = timestamp_regex.match(line)
108061da546Spatrick        if match:
109061da546Spatrick            curr_time = float(match.group(2))
110061da546Spatrick            delta = 0.0
111061da546Spatrick            if base_time:
112061da546Spatrick                delta = curr_time - last_time
113061da546Spatrick            else:
114061da546Spatrick                base_time = curr_time
115061da546Spatrick
116061da546Spatrick            print('%s%.6f %+.6f%s' % (match.group(1), curr_time - base_time, delta, match.group(3)))
117061da546Spatrick            last_time = curr_time
118061da546Spatrick        else:
119061da546Spatrick            print(line)
120061da546Spatrick
121061da546Spatrick
122061da546Spatrickif __name__ == '__main__':
123061da546Spatrick    import sys
124061da546Spatrick    parse_time_log_args(sys.argv[1:])
125061da546Spatrick
126*f6aab3d8Srobert
127*f6aab3d8Srobertdef __lldb_init_module(debugger, internal_dict):
128061da546Spatrick        # This initializer is being run from LLDB in the embedded command interpreter
129061da546Spatrick        # Add any commands contained in this module to LLDB
130*f6aab3d8Srobert        debugger.HandleCommand(
131*f6aab3d8Srobert            'command script add -o -f delta.parse_time_log parse_time_log')
132061da546Spatrick        print('The "parse_time_log" command is now installed and ready for use, type "parse_time_log --help" for more information')
133