1515bc8c1Sserge-sans-paille#!/usr/bin/env python 20f729e9bSGreg Clayton 30f729e9bSGreg Clayton#---------------------------------------------------------------------- 40f729e9bSGreg Clayton# This module will enable GDB remote packet logging when the 50f729e9bSGreg Clayton# 'start_gdb_log' command is called with a filename to log to. When the 60f729e9bSGreg Clayton# 'stop_gdb_log' command is called, it will disable the logging and 70f729e9bSGreg Clayton# print out statistics about how long commands took to execute and also 80f729e9bSGreg Clayton# will primnt ou 90f729e9bSGreg Clayton# Be sure to add the python path that points to the LLDB shared library. 100f729e9bSGreg Clayton# 110f729e9bSGreg Clayton# To use this in the embedded python interpreter using "lldb" just 120f729e9bSGreg Clayton# import it with the full path using the "command script import" 130f729e9bSGreg Clayton# command. This can be done from the LLDB command line: 140f729e9bSGreg Clayton# (lldb) command script import /path/to/gdbremote.py 150f729e9bSGreg Clayton# Or it can be added to your ~/.lldbinit file so this module is always 160f729e9bSGreg Clayton# available. 170f729e9bSGreg Clayton#---------------------------------------------------------------------- 180f729e9bSGreg Clayton 19525cd59fSSerge Gueltonfrom __future__ import print_function 20525cd59fSSerge Guelton 210f729e9bSGreg Claytonimport optparse 220f729e9bSGreg Claytonimport os 230f729e9bSGreg Claytonimport shlex 240f729e9bSGreg Claytonimport re 250f729e9bSGreg Claytonimport tempfile 260f729e9bSGreg Clayton 27b9c1b51eSKate Stone 280f729e9bSGreg Claytondef start_gdb_log(debugger, command, result, dict): 290f729e9bSGreg Clayton '''Start logging GDB remote packets by enabling logging with timestamps and 300f729e9bSGreg Clayton thread safe logging. Follow a call to this function with a call to "stop_gdb_log" 310f729e9bSGreg Clayton in order to dump out the commands.''' 320f729e9bSGreg Clayton global log_file 330f729e9bSGreg Clayton if log_file: 34b9c1b51eSKate Stone result.PutCString( 35b9c1b51eSKate Stone 'error: logging is already in progress with file "%s"', 36b9c1b51eSKate Stone log_file) 370f729e9bSGreg Clayton else: 380f729e9bSGreg Clayton args_len = len(args) 390f729e9bSGreg Clayton if args_len == 0: 400f729e9bSGreg Clayton log_file = tempfile.mktemp() 410f729e9bSGreg Clayton elif len(args) == 1: 420f729e9bSGreg Clayton log_file = args[0] 430f729e9bSGreg Clayton 440f729e9bSGreg Clayton if log_file: 45b9c1b51eSKate Stone debugger.HandleCommand( 46b9c1b51eSKate Stone 'log enable --threadsafe --timestamp --file "%s" gdb-remote packets' % 47b9c1b51eSKate Stone log_file) 48b9c1b51eSKate Stone result.PutCString( 49b9c1b51eSKate Stone "GDB packet logging enable with log file '%s'\nUse the 'stop_gdb_log' command to stop logging and show packet statistics." % 50b9c1b51eSKate Stone log_file) 510f729e9bSGreg Clayton return 520f729e9bSGreg Clayton 530f729e9bSGreg Clayton result.PutCString('error: invalid log file path') 540f729e9bSGreg Clayton result.PutCString(usage) 550f729e9bSGreg Clayton 56b9c1b51eSKate Stone 570f729e9bSGreg Claytondef parse_time_log(debugger, command, result, dict): 580f729e9bSGreg Clayton # Any commands whose names might be followed by more valid C identifier 590f729e9bSGreg Clayton # characters must be listed here 600f729e9bSGreg Clayton command_args = shlex.split(command) 6118eca8a0SGreg Clayton parse_time_log_args(command_args) 6218eca8a0SGreg Clayton 63b9c1b51eSKate Stone 6418eca8a0SGreg Claytondef parse_time_log_args(command_args): 650f729e9bSGreg Clayton usage = "usage: parse_time_log [options] [<LOGFILEPATH>]" 660f729e9bSGreg Clayton description = '''Parse a log file that contains timestamps and convert the timestamps to delta times between log lines.''' 67b9c1b51eSKate Stone parser = optparse.OptionParser( 68b9c1b51eSKate Stone description=description, 69b9c1b51eSKate Stone prog='parse_time_log', 70b9c1b51eSKate Stone usage=usage) 71b9c1b51eSKate Stone parser.add_option( 72b9c1b51eSKate Stone '-v', 73b9c1b51eSKate Stone '--verbose', 74b9c1b51eSKate Stone action='store_true', 75b9c1b51eSKate Stone dest='verbose', 76b9c1b51eSKate Stone help='display verbose debug info', 77b9c1b51eSKate Stone default=False) 780f729e9bSGreg Clayton try: 790f729e9bSGreg Clayton (options, args) = parser.parse_args(command_args) 800f729e9bSGreg Clayton except: 810f729e9bSGreg Clayton return 820f729e9bSGreg Clayton for log_file in args: 830f729e9bSGreg Clayton parse_log_file(log_file, options) 840f729e9bSGreg Clayton 85b9c1b51eSKate Stone 860f729e9bSGreg Claytondef parse_log_file(file, options): 870f729e9bSGreg Clayton '''Parse a log file that was contains timestamps. These logs are typically 880f729e9bSGreg Clayton generated using: 890f729e9bSGreg Clayton (lldb) log enable --threadsafe --timestamp --file <FILE> .... 900f729e9bSGreg Clayton 91d93c4a33SBruce Mitchener This log file will contain timestamps and this function will then normalize 920f729e9bSGreg Clayton those packets to be relative to the first value timestamp that is found and 930f729e9bSGreg Clayton show delta times between log lines and also keep track of how long it takes 940f729e9bSGreg Clayton for GDB remote commands to make a send/receive round trip. This can be 950f729e9bSGreg Clayton handy when trying to figure out why some operation in the debugger is taking 960f729e9bSGreg Clayton a long time during a preset set of debugger commands.''' 970f729e9bSGreg Clayton 98525cd59fSSerge Guelton print('#----------------------------------------------------------------------') 99525cd59fSSerge Guelton print("# Log file: '%s'" % file) 100525cd59fSSerge Guelton print('#----------------------------------------------------------------------') 10118eca8a0SGreg Clayton 1020f729e9bSGreg Clayton timestamp_regex = re.compile('(\s*)([1-9][0-9]+\.[0-9]+)([^0-9].*)$') 1030f729e9bSGreg Clayton 1040f729e9bSGreg Clayton base_time = 0.0 1050f729e9bSGreg Clayton last_time = 0.0 1060f729e9bSGreg Clayton file = open(file) 1070f729e9bSGreg Clayton lines = file.read().splitlines() 1080f729e9bSGreg Clayton for line in lines: 1090f729e9bSGreg Clayton match = timestamp_regex.match(line) 1100f729e9bSGreg Clayton if match: 1110f729e9bSGreg Clayton curr_time = float(match.group(2)) 1120f729e9bSGreg Clayton delta = 0.0 1130f729e9bSGreg Clayton if base_time: 1140f729e9bSGreg Clayton delta = curr_time - last_time 1150f729e9bSGreg Clayton else: 1160f729e9bSGreg Clayton base_time = curr_time 1170f729e9bSGreg Clayton 118525cd59fSSerge Guelton print('%s%.6f %+.6f%s' % (match.group(1), curr_time - base_time, delta, match.group(3))) 1190f729e9bSGreg Clayton last_time = curr_time 1200f729e9bSGreg Clayton else: 121525cd59fSSerge Guelton print(line) 1220f729e9bSGreg Clayton 1230f729e9bSGreg Clayton 1240f729e9bSGreg Claytonif __name__ == '__main__': 1250f729e9bSGreg Clayton import sys 12618eca8a0SGreg Clayton parse_time_log_args(sys.argv[1:]) 1270f729e9bSGreg Clayton 128*1441ffe6SDave Lee 129*1441ffe6SDave Leedef __lldb_init_module(debugger, internal_dict): 1300f729e9bSGreg Clayton # This initializer is being run from LLDB in the embedded command interpreter 1310f729e9bSGreg Clayton # Add any commands contained in this module to LLDB 132*1441ffe6SDave Lee debugger.HandleCommand( 133b9c1b51eSKate Stone 'command script add -f delta.parse_time_log parse_time_log') 134525cd59fSSerge Guelton print('The "parse_time_log" command is now installed and ready for use, type "parse_time_log --help" for more information') 135