blob: defda7bc7646b400d890ff9e330a251628504e34 [file] [log] [blame]
Greg Claytone2841632012-01-26 02:56:24 +00001#!/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
Greg Clayton374b6712015-07-02 22:22:45 +000019import binascii
Greg Claytone2841632012-01-26 02:56:24 +000020import commands
Greg Clayton25f82aa2015-05-22 23:00:59 +000021import math
Greg Claytone2841632012-01-26 02:56:24 +000022import optparse
23import os
Greg Claytone2841632012-01-26 02:56:24 +000024import re
Greg Clayton8ebb9a82012-06-01 20:23:54 +000025import shlex
26import string
27import sys
Greg Claytone2841632012-01-26 02:56:24 +000028import tempfile
Greg Clayton374b6712015-07-02 22:22:45 +000029import xml.etree.ElementTree as ET
Greg Claytone2841632012-01-26 02:56:24 +000030
Greg Claytonf51a23f2012-06-04 23:22:17 +000031#----------------------------------------------------------------------
32# Global variables
33#----------------------------------------------------------------------
34g_log_file = ''
35g_byte_order = 'little'
36
Greg Clayton8ebb9a82012-06-01 20:23:54 +000037class TerminalColors:
38 '''Simple terminal colors class'''
Greg Claytonf51a23f2012-06-04 23:22:17 +000039 def __init__(self, enabled = True):
Greg Clayton8ebb9a82012-06-01 20:23:54 +000040 # TODO: discover terminal type from "file" and disable if
41 # it can't handle the color codes
42 self.enabled = enabled
43
44 def reset(self):
45 '''Reset all terminal colors and formatting.'''
46 if self.enabled:
Greg Claytonf51a23f2012-06-04 23:22:17 +000047 return "\x1b[0m";
48 return ''
Greg Clayton8ebb9a82012-06-01 20:23:54 +000049
50 def bold(self, on = True):
Bruce Mitchenerd93c4a32014-07-01 21:22:11 +000051 '''Enable or disable bold depending on the "on" parameter.'''
Greg Clayton8ebb9a82012-06-01 20:23:54 +000052 if self.enabled:
53 if on:
Greg Claytonf51a23f2012-06-04 23:22:17 +000054 return "\x1b[1m";
Greg Clayton8ebb9a82012-06-01 20:23:54 +000055 else:
Greg Claytonf51a23f2012-06-04 23:22:17 +000056 return "\x1b[22m";
57 return ''
58
Greg Clayton8ebb9a82012-06-01 20:23:54 +000059 def italics(self, on = True):
Bruce Mitchenerd93c4a32014-07-01 21:22:11 +000060 '''Enable or disable italics depending on the "on" parameter.'''
Greg Clayton8ebb9a82012-06-01 20:23:54 +000061 if self.enabled:
62 if on:
Greg Claytonf51a23f2012-06-04 23:22:17 +000063 return "\x1b[3m";
Greg Clayton8ebb9a82012-06-01 20:23:54 +000064 else:
Greg Claytonf51a23f2012-06-04 23:22:17 +000065 return "\x1b[23m";
66 return ''
67
Greg Clayton8ebb9a82012-06-01 20:23:54 +000068 def underline(self, on = True):
Bruce Mitchenerd93c4a32014-07-01 21:22:11 +000069 '''Enable or disable underline depending on the "on" parameter.'''
Greg Clayton8ebb9a82012-06-01 20:23:54 +000070 if self.enabled:
71 if on:
Greg Claytonf51a23f2012-06-04 23:22:17 +000072 return "\x1b[4m";
Greg Clayton8ebb9a82012-06-01 20:23:54 +000073 else:
Greg Claytonf51a23f2012-06-04 23:22:17 +000074 return "\x1b[24m";
75 return ''
76
Greg Clayton8ebb9a82012-06-01 20:23:54 +000077 def inverse(self, on = True):
Bruce Mitchenerd93c4a32014-07-01 21:22:11 +000078 '''Enable or disable inverse depending on the "on" parameter.'''
Greg Clayton8ebb9a82012-06-01 20:23:54 +000079 if self.enabled:
80 if on:
Greg Claytonf51a23f2012-06-04 23:22:17 +000081 return "\x1b[7m";
Greg Clayton8ebb9a82012-06-01 20:23:54 +000082 else:
Greg Claytonf51a23f2012-06-04 23:22:17 +000083 return "\x1b[27m";
84 return ''
85
Greg Clayton8ebb9a82012-06-01 20:23:54 +000086 def strike(self, on = True):
Bruce Mitchenerd93c4a32014-07-01 21:22:11 +000087 '''Enable or disable strike through depending on the "on" parameter.'''
Greg Clayton8ebb9a82012-06-01 20:23:54 +000088 if self.enabled:
89 if on:
Greg Claytonf51a23f2012-06-04 23:22:17 +000090 return "\x1b[9m";
Greg Clayton8ebb9a82012-06-01 20:23:54 +000091 else:
Greg Claytonf51a23f2012-06-04 23:22:17 +000092 return "\x1b[29m";
93 return ''
94
Greg Clayton8ebb9a82012-06-01 20:23:54 +000095 def black(self, fg = True):
96 '''Set the foreground or background color to black.
97 The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
98 if self.enabled:
99 if fg:
Greg Claytonf51a23f2012-06-04 23:22:17 +0000100 return "\x1b[30m";
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000101 else:
Greg Claytonf51a23f2012-06-04 23:22:17 +0000102 return "\x1b[40m";
103 return ''
104
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000105 def red(self, fg = True):
106 '''Set the foreground or background color to red.
107 The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
108 if self.enabled:
109 if fg:
Greg Claytonf51a23f2012-06-04 23:22:17 +0000110 return "\x1b[31m";
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000111 else:
Greg Claytonf51a23f2012-06-04 23:22:17 +0000112 return "\x1b[41m";
113 return ''
114
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000115 def green(self, fg = True):
116 '''Set the foreground or background color to green.
117 The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
118 if self.enabled:
119 if fg:
Greg Claytonf51a23f2012-06-04 23:22:17 +0000120 return "\x1b[32m";
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000121 else:
Greg Claytonf51a23f2012-06-04 23:22:17 +0000122 return "\x1b[42m";
123 return ''
124
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000125 def yellow(self, fg = True):
126 '''Set the foreground or background color to yellow.
127 The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
128 if self.enabled:
129 if fg:
Greg Claytonf51a23f2012-06-04 23:22:17 +0000130 return "\x1b[43m";
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000131 else:
Greg Claytonf51a23f2012-06-04 23:22:17 +0000132 return "\x1b[33m";
133 return ''
134
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000135 def blue(self, fg = True):
136 '''Set the foreground or background color to blue.
137 The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
138 if self.enabled:
139 if fg:
Greg Claytonf51a23f2012-06-04 23:22:17 +0000140 return "\x1b[34m";
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000141 else:
Greg Claytonf51a23f2012-06-04 23:22:17 +0000142 return "\x1b[44m";
143 return ''
144
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000145 def magenta(self, fg = True):
146 '''Set the foreground or background color to magenta.
147 The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
148 if self.enabled:
149 if fg:
Greg Claytonf51a23f2012-06-04 23:22:17 +0000150 return "\x1b[35m";
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000151 else:
Greg Claytonf51a23f2012-06-04 23:22:17 +0000152 return "\x1b[45m";
153 return ''
154
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000155 def cyan(self, fg = True):
156 '''Set the foreground or background color to cyan.
157 The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
158 if self.enabled:
159 if fg:
Greg Claytonf51a23f2012-06-04 23:22:17 +0000160 return "\x1b[36m";
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000161 else:
Greg Claytonf51a23f2012-06-04 23:22:17 +0000162 return "\x1b[46m";
163 return ''
164
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000165 def white(self, fg = True):
166 '''Set the foreground or background color to white.
167 The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
168 if self.enabled:
169 if fg:
Greg Claytonf51a23f2012-06-04 23:22:17 +0000170 return "\x1b[37m";
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000171 else:
Greg Claytonf51a23f2012-06-04 23:22:17 +0000172 return "\x1b[47m";
173 return ''
174
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000175 def default(self, fg = True):
176 '''Set the foreground or background color to the default.
177 The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
178 if self.enabled:
179 if fg:
Greg Claytonf51a23f2012-06-04 23:22:17 +0000180 return "\x1b[39m";
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000181 else:
Greg Claytonf51a23f2012-06-04 23:22:17 +0000182 return "\x1b[49m";
183 return ''
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000184
Greg Claytone2841632012-01-26 02:56:24 +0000185
186def start_gdb_log(debugger, command, result, dict):
187 '''Start logging GDB remote packets by enabling logging with timestamps and
188 thread safe logging. Follow a call to this function with a call to "stop_gdb_log"
189 in order to dump out the commands.'''
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000190 global g_log_file
Greg Claytone2841632012-01-26 02:56:24 +0000191 command_args = shlex.split(command)
192 usage = "usage: start_gdb_log [options] [<LOGFILEPATH>]"
193 description='''The command enables GDB remote packet logging with timestamps. The packets will be logged to <LOGFILEPATH> if supplied, or a temporary file will be used. Logging stops when stop_gdb_log is called and the packet times will
194 be aggregated and displayed.'''
195 parser = optparse.OptionParser(description=description, prog='start_gdb_log',usage=usage)
196 parser.add_option('-v', '--verbose', action='store_true', dest='verbose', help='display verbose debug info', default=False)
197 try:
198 (options, args) = parser.parse_args(command_args)
199 except:
200 return
201
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000202 if g_log_file:
203 result.PutCString ('error: logging is already in progress with file "%s"', g_log_file)
Greg Claytone2841632012-01-26 02:56:24 +0000204 else:
205 args_len = len(args)
206 if args_len == 0:
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000207 g_log_file = tempfile.mktemp()
Greg Claytone2841632012-01-26 02:56:24 +0000208 elif len(args) == 1:
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000209 g_log_file = args[0]
Greg Claytone2841632012-01-26 02:56:24 +0000210
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000211 if g_log_file:
212 debugger.HandleCommand('log enable --threadsafe --timestamp --file "%s" gdb-remote packets' % g_log_file);
213 result.PutCString ("GDB packet logging enable with log file '%s'\nUse the 'stop_gdb_log' command to stop logging and show packet statistics." % g_log_file)
Greg Claytone2841632012-01-26 02:56:24 +0000214 return
215
216 result.PutCString ('error: invalid log file path')
217 result.PutCString (usage)
218
219def stop_gdb_log(debugger, command, result, dict):
220 '''Stop logging GDB remote packets to the file that was specified in a call
221 to "start_gdb_log" and normalize the timestamps to be relative to the first
222 timestamp in the log file. Also print out statistics for how long each
223 command took to allow performance bottlenecks to be determined.'''
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000224 global g_log_file
Greg Claytone2841632012-01-26 02:56:24 +0000225 # Any commands whose names might be followed by more valid C identifier
226 # characters must be listed here
227 command_args = shlex.split(command)
228 usage = "usage: stop_gdb_log [options]"
229 description='''The command stops a previously enabled GDB remote packet logging command. Packet logging must have been previously enabled with a call to start_gdb_log.'''
230 parser = optparse.OptionParser(description=description, prog='stop_gdb_log',usage=usage)
231 parser.add_option('-v', '--verbose', action='store_true', dest='verbose', help='display verbose debug info', default=False)
232 parser.add_option('-q', '--quiet', action='store_true', dest='quiet', help='display verbose debug info', default=False)
Greg Claytonf51a23f2012-06-04 23:22:17 +0000233 parser.add_option('-C', '--color', action='store_true', dest='color', help='add terminal colors', default=False)
Jim Inghamd95752f2012-03-01 18:57:51 +0000234 parser.add_option('-c', '--sort-by-count', action='store_true', dest='sort_count', help='display verbose debug info', default=False)
Greg Claytonf51a23f2012-06-04 23:22:17 +0000235 parser.add_option('-s', '--symbolicate', action='store_true', dest='symbolicate', help='symbolicate addresses in log using current "lldb.target"', default=False)
Greg Claytone2841632012-01-26 02:56:24 +0000236 try:
237 (options, args) = parser.parse_args(command_args)
238 except:
239 return
Greg Claytonf51a23f2012-06-04 23:22:17 +0000240 options.colors = TerminalColors(options.color)
241 options.symbolicator = None
242 if options.symbolicate:
243 if lldb.target:
244 import lldb.utils.symbolication
245 options.symbolicator = lldb.utils.symbolication.Symbolicator()
246 options.symbolicator.target = lldb.target
247 else:
248 print "error: can't symbolicate without a target"
Greg Claytone2841632012-01-26 02:56:24 +0000249
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000250 if not g_log_file:
Greg Claytone2841632012-01-26 02:56:24 +0000251 result.PutCString ('error: logging must have been previously enabled with a call to "stop_gdb_log"')
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000252 elif os.path.exists (g_log_file):
Greg Claytone2841632012-01-26 02:56:24 +0000253 if len(args) == 0:
254 debugger.HandleCommand('log disable gdb-remote packets');
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000255 result.PutCString ("GDB packet logging disabled. Logged packets are in '%s'" % g_log_file)
256 parse_gdb_log_file (g_log_file, options)
Greg Claytone2841632012-01-26 02:56:24 +0000257 else:
258 result.PutCString (usage)
259 else:
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000260 print 'error: the GDB packet log file "%s" does not exist' % g_log_file
Greg Claytone2841632012-01-26 02:56:24 +0000261
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000262def is_hex_byte(str):
263 if len(str) == 2:
264 return str[0] in string.hexdigits and str[1] in string.hexdigits;
265 return False
266
267# global register info list
268g_register_infos = list()
269g_max_register_info_name_len = 0
270
271class RegisterInfo:
272 """Class that represents register information"""
273 def __init__(self, kvp):
274 self.info = dict()
275 for kv in kvp:
276 key = kv[0]
277 value = kv[1]
278 self.info[key] = value
279 def name(self):
280 '''Get the name of the register.'''
281 if self.info and 'name' in self.info:
282 return self.info['name']
283 return None
284
285 def bit_size(self):
286 '''Get the size in bits of the register.'''
287 if self.info and 'bitsize' in self.info:
288 return int(self.info['bitsize'])
289 return 0
290
291 def byte_size(self):
292 '''Get the size in bytes of the register.'''
293 return self.bit_size() / 8
294
295 def get_value_from_hex_string(self, hex_str):
296 '''Dump the register value given a native byte order encoded hex ASCII byte string.'''
297 encoding = self.info['encoding']
298 bit_size = self.bit_size()
299 packet = Packet(hex_str)
300 if encoding == 'uint':
301 uval = packet.get_hex_uint(g_byte_order)
302 if bit_size == 8:
303 return '0x%2.2x' % (uval)
304 elif bit_size == 16:
305 return '0x%4.4x' % (uval)
306 elif bit_size == 32:
307 return '0x%8.8x' % (uval)
308 elif bit_size == 64:
309 return '0x%16.16x' % (uval)
310 bytes = list();
311 uval = packet.get_hex_uint8()
312 while uval != None:
313 bytes.append(uval)
314 uval = packet.get_hex_uint8()
315 value_str = '0x'
316 if g_byte_order == 'little':
317 bytes.reverse()
318 for byte in bytes:
319 value_str += '%2.2x' % byte
320 return '%s' % (value_str)
321
322 def __str__(self):
323 '''Dump the register info key/value pairs'''
324 s = ''
325 for key in self.info.keys():
326 if s:
327 s += ', '
328 s += "%s=%s " % (key, self.info[key])
329 return s
330
331class Packet:
332 """Class that represents a packet that contains string data"""
333 def __init__(self, packet_str):
334 self.str = packet_str
335
336 def peek_char(self):
337 ch = 0
338 if self.str:
339 ch = self.str[0]
340 return ch
341
342 def get_char(self):
343 ch = 0
344 if self.str:
345 ch = self.str[0]
346 self.str = self.str[1:]
347 return ch
348
349 def get_hex_uint8(self):
350 if self.str and len(self.str) >= 2 and self.str[0] in string.hexdigits and self.str[1] in string.hexdigits:
351 uval = int(self.str[0:2], 16)
352 self.str = self.str[2:]
353 return uval
354 return None
355
356 def get_hex_uint16(self, byte_order):
357 uval = 0
358 if byte_order == 'big':
359 uval |= self.get_hex_uint8() << 8
360 uval |= self.get_hex_uint8()
361 else:
362 uval |= self.get_hex_uint8()
363 uval |= self.get_hex_uint8() << 8
364 return uval
365
366 def get_hex_uint32(self, byte_order):
367 uval = 0
368 if byte_order == 'big':
369 uval |= self.get_hex_uint8() << 24
370 uval |= self.get_hex_uint8() << 16
371 uval |= self.get_hex_uint8() << 8
372 uval |= self.get_hex_uint8()
373 else:
374 uval |= self.get_hex_uint8()
375 uval |= self.get_hex_uint8() << 8
376 uval |= self.get_hex_uint8() << 16
377 uval |= self.get_hex_uint8() << 24
378 return uval
379
380 def get_hex_uint64(self, byte_order):
381 uval = 0
382 if byte_order == 'big':
383 uval |= self.get_hex_uint8() << 56
384 uval |= self.get_hex_uint8() << 48
385 uval |= self.get_hex_uint8() << 40
386 uval |= self.get_hex_uint8() << 32
387 uval |= self.get_hex_uint8() << 24
388 uval |= self.get_hex_uint8() << 16
389 uval |= self.get_hex_uint8() << 8
390 uval |= self.get_hex_uint8()
391 else:
392 uval |= self.get_hex_uint8()
393 uval |= self.get_hex_uint8() << 8
394 uval |= self.get_hex_uint8() << 16
395 uval |= self.get_hex_uint8() << 24
396 uval |= self.get_hex_uint8() << 32
397 uval |= self.get_hex_uint8() << 40
398 uval |= self.get_hex_uint8() << 48
399 uval |= self.get_hex_uint8() << 56
400 return uval
401
Greg Clayton374b6712015-07-02 22:22:45 +0000402 def get_hex_ascii_str(self, n=0):
403 hex_chars = self.get_hex_chars(n)
404 if hex_chars:
405 return binascii.unhexlify(hex_chars)
406 else:
407 return None
408
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000409 def get_hex_chars(self, n = 0):
410 str_len = len(self.str)
411 if n == 0:
412 # n was zero, so we need to determine all hex chars and
413 # stop when we hit the end of the string of a non-hex character
414 while n < str_len and self.str[n] in string.hexdigits:
415 n = n + 1
416 else:
417 if n > str_len:
418 return None # Not enough chars
419 # Verify all chars are hex if a length was specified
420 for i in range(n):
421 if self.str[i] not in string.hexdigits:
422 return None # Not all hex digits
423 if n == 0:
424 return None
425 hex_str = self.str[0:n]
426 self.str = self.str[n:]
427 return hex_str
428
429 def get_hex_uint(self, byte_order, n = 0):
430 if byte_order == 'big':
431 hex_str = self.get_hex_chars(n)
432 if hex_str == None:
433 return None
434 return int(hex_str, 16)
435 else:
436 uval = self.get_hex_uint8()
437 if uval == None:
438 return None
439 uval_result = 0
440 shift = 0
441 while uval != None:
442 uval_result |= (uval << shift)
443 shift += 8
444 uval = self.get_hex_uint8()
445 return uval_result
446
447 def get_key_value_pairs(self):
448 kvp = list()
Greg Clayton25f82aa2015-05-22 23:00:59 +0000449 if ';' in self.str:
450 key_value_pairs = string.split(self.str, ';')
451 for key_value_pair in key_value_pairs:
452 if len(key_value_pair):
453 kvp.append(string.split(key_value_pair, ':'))
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000454 return kvp
455
456 def split(self, ch):
457 return string.split(self.str, ch)
458
459 def split_hex(self, ch, byte_order):
460 hex_values = list()
461 strings = string.split(self.str, ch)
462 for str in strings:
463 hex_values.append(Packet(str).get_hex_uint(byte_order))
464 return hex_values
465
466 def __str__(self):
467 return self.str
468
469 def __len__(self):
470 return len(self.str)
471
472g_thread_suffix_regex = re.compile(';thread:([0-9a-fA-F]+);')
473def get_thread_from_thread_suffix(str):
474 if str:
475 match = g_thread_suffix_regex.match (str)
476 if match:
477 return int(match.group(1), 16)
478 return None
479
Greg Claytonf51a23f2012-06-04 23:22:17 +0000480def cmd_stop_reply(options, cmd, args):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000481 print "get_last_stop_info()"
482
Greg Claytonf51a23f2012-06-04 23:22:17 +0000483def rsp_stop_reply(options, cmd, cmd_args, rsp):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000484 global g_byte_order
485 packet = Packet(rsp)
486 stop_type = packet.get_char()
487 if stop_type == 'T' or stop_type == 'S':
488 signo = packet.get_hex_uint8()
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000489 key_value_pairs = packet.get_key_value_pairs()
490 for key_value_pair in key_value_pairs:
491 key = key_value_pair[0]
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000492 if is_hex_byte(key):
493 reg_num = Packet(key).get_hex_uint8()
Greg Clayton374b6712015-07-02 22:22:45 +0000494 if reg_num < len(g_register_infos):
495 reg_info = g_register_infos[reg_num]
496 key_value_pair[0] = reg_info.name()
497 key_value_pair[1] = reg_info.get_value_from_hex_string (key_value_pair[1])
498 key_value_pairs.insert(0, ['signal', signo])
499 dump_key_value_pairs (key_value_pairs)
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000500 elif stop_type == 'W':
501 exit_status = packet.get_hex_uint8()
502 print 'exit (status=%i)' % exit_status
503 elif stop_type == 'O':
504 print 'stdout = %s' % packet.str
505
506
Greg Claytonf51a23f2012-06-04 23:22:17 +0000507def cmd_unknown_packet(options, cmd, args):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000508 if args:
509 print "cmd: %s, args: %s", cmd, args
510 else:
511 print "cmd: %s", cmd
512
Greg Clayton374b6712015-07-02 22:22:45 +0000513def cmd_qXfer(options, cmd, args):
514 # $qXfer:features:read:target.xml:0,1ffff#14
515 print "read target special data %s" % (args)
516
517def rsp_qXfer(options, cmd, cmd_args, rsp):
518 data = string.split(cmd_args, ':')
519 if data[0] == 'features':
520 if data[1] == 'read':
521 filename, extension = os.path.splitext(data[2])
522 if extension == '.xml':
523 response = Packet(rsp)
524 xml_string = response.get_hex_ascii_str()
525 ch = xml_string[0]
526 if ch == 'l':
527 xml_string = xml_string[1:]
528 xml_root = ET.fromstring(xml_string)
529 for reg_element in xml_root.findall("./feature/reg"):
530 if not 'value_regnums' in reg_element.attrib:
531 reg_info = RegisterInfo([])
532 if 'name' in reg_element.attrib:
533 reg_info.info['name'] = reg_element.attrib['name']
534 else:
535 reg_info.info['name'] = 'unspecified'
536 if 'encoding' in reg_element.attrib:
537 reg_info.info['encoding'] = reg_element.attrib['encoding']
538 else:
539 reg_info.info['encoding'] = 'uint'
540 if 'offset' in reg_element.attrib:
541 reg_info.info['offset'] = reg_element.attrib['offset']
542 if 'bitsize' in reg_element.attrib:
543 reg_info.info['bitsize'] = reg_element.attrib['bitsize']
544 g_register_infos.append(reg_info)
545
546
Greg Claytonf51a23f2012-06-04 23:22:17 +0000547def cmd_query_packet(options, cmd, args):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000548 if args:
Greg Claytonf51a23f2012-06-04 23:22:17 +0000549 print "query: %s, args: %s" % (cmd, args)
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000550 else:
Greg Claytonf51a23f2012-06-04 23:22:17 +0000551 print "query: %s" % (cmd)
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000552
553def rsp_ok_error(rsp):
554 print "rsp: ", rsp
555
Greg Claytonf51a23f2012-06-04 23:22:17 +0000556def rsp_ok_means_supported(options, cmd, cmd_args, rsp):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000557 if rsp == 'OK':
558 print "%s%s is supported" % (cmd, cmd_args)
559 elif rsp == '':
560 print "%s%s is not supported" % (cmd, cmd_args)
561 else:
562 print "%s%s -> %s" % (cmd, cmd_args, rsp)
563
Greg Claytonf51a23f2012-06-04 23:22:17 +0000564def rsp_ok_means_success(options, cmd, cmd_args, rsp):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000565 if rsp == 'OK':
566 print "success"
567 elif rsp == '':
568 print "%s%s is not supported" % (cmd, cmd_args)
569 else:
570 print "%s%s -> %s" % (cmd, cmd_args, rsp)
571
Greg Clayton374b6712015-07-02 22:22:45 +0000572def dump_key_value_pairs(key_value_pairs):
573 max_key_len = 0
574 for key_value_pair in key_value_pairs:
575 key_len = len(key_value_pair[0])
576 if max_key_len < key_len:
577 max_key_len = key_len
578 for key_value_pair in key_value_pairs:
579 key = key_value_pair[0]
580 value = key_value_pair[1]
581 print "%*s = %s" % (max_key_len, key, value)
582
Greg Claytonf51a23f2012-06-04 23:22:17 +0000583def rsp_dump_key_value_pairs(options, cmd, cmd_args, rsp):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000584 if rsp:
585 packet = Packet(rsp)
586 key_value_pairs = packet.get_key_value_pairs()
Greg Clayton374b6712015-07-02 22:22:45 +0000587 dump_key_value_pairs(key_value_pairs)
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000588 else:
589 print "not supported"
590
Greg Claytonf51a23f2012-06-04 23:22:17 +0000591def cmd_vCont(options, cmd, args):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000592 if args == '?':
593 print "%s: get supported extended continue modes" % (cmd)
594 else:
595 got_other_threads = 0
596 s = ''
597 for thread_action in string.split(args[1:], ';'):
598 (short_action, thread) = string.split(thread_action, ':')
599 tid = int(thread, 16)
600 if short_action == 'c':
601 action = 'continue'
602 elif short_action == 's':
603 action = 'step'
604 elif short_action[0] == 'C':
605 action = 'continue with signal 0x%s' % (short_action[1:])
606 elif short_action == 'S':
607 action = 'step with signal 0x%s' % (short_action[1:])
608 else:
609 action = short_action
610 if s:
611 s += ', '
612 if tid == -1:
613 got_other_threads = 1
614 s += 'other-threads:'
615 else:
616 s += 'thread 0x%4.4x: %s' % (tid, action)
617 if got_other_threads:
618 print "extended_continue (%s)" % (s)
619 else:
620 print "extended_continue (%s, other-threads: suspend)" % (s)
621
Greg Claytonf51a23f2012-06-04 23:22:17 +0000622def rsp_vCont(options, cmd, cmd_args, rsp):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000623 if cmd_args == '?':
624 # Skip the leading 'vCont;'
625 rsp = rsp[6:]
626 modes = string.split(rsp, ';')
627 s = "%s: supported extended continue modes include: " % (cmd)
628
629 for i, mode in enumerate(modes):
630 if i:
631 s += ', '
632 if mode == 'c':
633 s += 'continue'
634 elif mode == 'C':
635 s += 'continue with signal'
636 elif mode == 's':
637 s += 'step'
638 elif mode == 'S':
639 s += 'step with signal'
640 else:
641 s += 'unrecognized vCont mode: ', mode
642 print s
643 elif rsp:
644 if rsp[0] == 'T' or rsp[0] == 'S' or rsp[0] == 'W' or rsp[0] == 'X':
Greg Claytonf51a23f2012-06-04 23:22:17 +0000645 rsp_stop_reply (options, cmd, cmd_args, rsp)
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000646 return
647 if rsp[0] == 'O':
648 print "stdout: %s" % (rsp)
649 return
650 else:
651 print "not supported (cmd = '%s', args = '%s', rsp = '%s')" % (cmd, cmd_args, rsp)
652
Greg Claytonf51a23f2012-06-04 23:22:17 +0000653def cmd_vAttach(options, cmd, args):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000654 (extra_command, args) = string.split(args, ';')
655 if extra_command:
656 print "%s%s(%s)" % (cmd, extra_command, args)
657 else:
658 print "attach_pid(%s)" % args
659
Greg Claytonf51a23f2012-06-04 23:22:17 +0000660def cmd_qRegisterInfo(options, cmd, args):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000661 print 'query_register_info(reg_num=%i)' % (int(args, 16))
662
Greg Claytonf51a23f2012-06-04 23:22:17 +0000663def rsp_qRegisterInfo(options, cmd, cmd_args, rsp):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000664 global g_max_register_info_name_len
665 print 'query_register_info(reg_num=%i):' % (int(cmd_args, 16)),
666 if len(rsp) == 3 and rsp[0] == 'E':
667 g_max_register_info_name_len = 0
668 for reg_info in g_register_infos:
669 name_len = len(reg_info.name())
670 if g_max_register_info_name_len < name_len:
671 g_max_register_info_name_len = name_len
672 print' DONE'
673 else:
674 packet = Packet(rsp)
675 reg_info = RegisterInfo(packet.get_key_value_pairs())
676 g_register_infos.append(reg_info)
677 print reg_info
678
679
Greg Claytonf51a23f2012-06-04 23:22:17 +0000680def cmd_qThreadInfo(options, cmd, args):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000681 if cmd == 'qfThreadInfo':
682 query_type = 'first'
683 else:
684 query_type = 'subsequent'
685 print 'get_current_thread_list(type=%s)' % (query_type)
686
Greg Claytonf51a23f2012-06-04 23:22:17 +0000687def rsp_qThreadInfo(options, cmd, cmd_args, rsp):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000688 packet = Packet(rsp)
689 response_type = packet.get_char()
690 if response_type == 'm':
691 tids = packet.split_hex(';', 'big')
692 for i, tid in enumerate(tids):
693 if i:
694 print ',',
695 print '0x%x' % (tid),
696 print
697 elif response_type == 'l':
698 print 'END'
699
Greg Claytonf51a23f2012-06-04 23:22:17 +0000700def rsp_hex_big_endian(options, cmd, cmd_args, rsp):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000701 packet = Packet(rsp)
702 uval = packet.get_hex_uint('big')
703 print '%s: 0x%x' % (cmd, uval)
704
Greg Claytonf51a23f2012-06-04 23:22:17 +0000705def cmd_read_memory(options, cmd, args):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000706 packet = Packet(args)
707 addr = packet.get_hex_uint('big')
708 comma = packet.get_char()
709 size = packet.get_hex_uint('big')
710 print 'read_memory (addr = 0x%x, size = %u)' % (addr, size)
711
712def dump_hex_memory_buffer(addr, hex_byte_str):
713 packet = Packet(hex_byte_str)
714 idx = 0
715 ascii = ''
716 uval = packet.get_hex_uint8()
717 while uval != None:
718 if ((idx % 16) == 0):
719 if ascii:
720 print ' ', ascii
721 ascii = ''
722 print '0x%x:' % (addr + idx),
723 print '%2.2x' % (uval),
724 if 0x20 <= uval and uval < 0x7f:
725 ascii += '%c' % uval
726 else:
727 ascii += '.'
728 uval = packet.get_hex_uint8()
729 idx = idx + 1
730 if ascii:
731 print ' ', ascii
732 ascii = ''
733
Greg Claytonf51a23f2012-06-04 23:22:17 +0000734def cmd_write_memory(options, cmd, args):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000735 packet = Packet(args)
736 addr = packet.get_hex_uint('big')
737 if packet.get_char() != ',':
738 print 'error: invalid write memory command (missing comma after address)'
739 return
740 size = packet.get_hex_uint('big')
741 if packet.get_char() != ':':
742 print 'error: invalid write memory command (missing colon after size)'
743 return
744 print 'write_memory (addr = 0x%x, size = %u, data:' % (addr, size)
745 dump_hex_memory_buffer (addr, packet.str)
746
Greg Claytonf51a23f2012-06-04 23:22:17 +0000747def cmd_alloc_memory(options, cmd, args):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000748 packet = Packet(args)
749 byte_size = packet.get_hex_uint('big')
750 if packet.get_char() != ',':
751 print 'error: invalid allocate memory command (missing comma after address)'
752 return
753 print 'allocate_memory (byte-size = %u (0x%x), permissions = %s)' % (byte_size, byte_size, packet.str)
754
Greg Claytonf51a23f2012-06-04 23:22:17 +0000755def rsp_alloc_memory(options, cmd, cmd_args, rsp):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000756 packet = Packet(rsp)
757 addr = packet.get_hex_uint('big')
758 print 'addr = 0x%x' % addr
759
Greg Claytonf51a23f2012-06-04 23:22:17 +0000760def cmd_dealloc_memory(options, cmd, args):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000761 packet = Packet(args)
762 addr = packet.get_hex_uint('big')
763 if packet.get_char() != ',':
764 print 'error: invalid allocate memory command (missing comma after address)'
765 return
766 print 'deallocate_memory (addr = 0x%x, permissions = %s)' % (addr, packet.str)
767
Greg Claytonf51a23f2012-06-04 23:22:17 +0000768def rsp_memory_bytes(options, cmd, cmd_args, rsp):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000769 addr = Packet(cmd_args).get_hex_uint('big')
770 dump_hex_memory_buffer (addr, rsp)
771
Greg Claytonf51a23f2012-06-04 23:22:17 +0000772def get_register_name_equal_value(options, reg_num, hex_value_str):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000773 if reg_num < len(g_register_infos):
774 reg_info = g_register_infos[reg_num]
Greg Claytonf51a23f2012-06-04 23:22:17 +0000775 value_str = reg_info.get_value_from_hex_string (hex_value_str)
776 s = reg_info.name() + ' = '
777 if options.symbolicator:
778 symbolicated_addresses = options.symbolicator.symbolicate (int(value_str, 0))
779 if symbolicated_addresses:
780 s += options.colors.magenta()
781 s += '%s' % symbolicated_addresses[0]
782 s += options.colors.reset()
783 return s
784 s += value_str
785 return s
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000786 else:
787 reg_value = Packet(hex_value_str).get_hex_uint(g_byte_order)
788 return 'reg(%u) = 0x%x' % (reg_num, reg_value)
789
Greg Claytonf51a23f2012-06-04 23:22:17 +0000790def cmd_read_one_reg(options, cmd, args):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000791 packet = Packet(args)
792 reg_num = packet.get_hex_uint('big')
793 tid = get_thread_from_thread_suffix (packet.str)
794 name = None
795 if reg_num < len(g_register_infos):
796 name = g_register_infos[reg_num].name ()
797 if packet.str:
798 packet.get_char() # skip ;
799 thread_info = packet.get_key_value_pairs()
800 tid = int(thread_info[0][1], 16)
801 s = 'read_register (reg_num=%u' % reg_num
802 if name:
803 s += ' (%s)' % (name)
804 if tid != None:
805 s += ', tid = 0x%4.4x' % (tid)
806 s += ')'
807 print s
808
Greg Claytonf51a23f2012-06-04 23:22:17 +0000809def rsp_read_one_reg(options, cmd, cmd_args, rsp):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000810 packet = Packet(cmd_args)
811 reg_num = packet.get_hex_uint('big')
Greg Claytonf51a23f2012-06-04 23:22:17 +0000812 print get_register_name_equal_value (options, reg_num, rsp)
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000813
Greg Claytonf51a23f2012-06-04 23:22:17 +0000814def cmd_write_one_reg(options, cmd, args):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000815 packet = Packet(args)
816 reg_num = packet.get_hex_uint('big')
817 if packet.get_char() != '=':
818 print 'error: invalid register write packet'
819 else:
820 name = None
821 hex_value_str = packet.get_hex_chars()
822 tid = get_thread_from_thread_suffix (packet.str)
823 s = 'write_register (reg_num=%u' % reg_num
824 if name:
825 s += ' (%s)' % (name)
826 s += ', value = '
Greg Claytonf51a23f2012-06-04 23:22:17 +0000827 s += get_register_name_equal_value(options, reg_num, hex_value_str)
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000828 if tid != None:
829 s += ', tid = 0x%4.4x' % (tid)
830 s += ')'
831 print s
832
833def dump_all_regs(packet):
834 for reg_info in g_register_infos:
835 nibble_size = reg_info.bit_size() / 4
836 hex_value_str = packet.get_hex_chars(nibble_size)
837 if hex_value_str != None:
838 value = reg_info.get_value_from_hex_string (hex_value_str)
839 print '%*s = %s' % (g_max_register_info_name_len, reg_info.name(), value)
840 else:
841 return
842
843def cmd_read_all_regs(cmd, cmd_args):
844 packet = Packet(cmd_args)
845 packet.get_char() # toss the 'g' command character
846 tid = get_thread_from_thread_suffix (packet.str)
847 if tid != None:
848 print 'read_all_register(thread = 0x%4.4x)' % tid
849 else:
850 print 'read_all_register()'
851
Greg Claytonf51a23f2012-06-04 23:22:17 +0000852def rsp_read_all_regs(options, cmd, cmd_args, rsp):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000853 packet = Packet(rsp)
854 dump_all_regs (packet)
855
Greg Claytonf51a23f2012-06-04 23:22:17 +0000856def cmd_write_all_regs(options, cmd, args):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000857 packet = Packet(args)
858 print 'write_all_registers()'
859 dump_all_regs (packet)
860
861g_bp_types = [ "software_bp", "hardware_bp", "write_wp", "read_wp", "access_wp" ]
862
Greg Claytonf51a23f2012-06-04 23:22:17 +0000863def cmd_bp(options, cmd, args):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000864 if cmd == 'Z':
865 s = 'set_'
866 else:
867 s = 'clear_'
868 packet = Packet (args)
869 bp_type = packet.get_hex_uint('big')
870 packet.get_char() # Skip ,
871 bp_addr = packet.get_hex_uint('big')
872 packet.get_char() # Skip ,
873 bp_size = packet.get_hex_uint('big')
874 s += g_bp_types[bp_type]
875 s += " (addr = 0x%x, size = %u)" % (bp_addr, bp_size)
876 print s
877
Greg Claytonf51a23f2012-06-04 23:22:17 +0000878def cmd_mem_rgn_info(options, cmd, args):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000879 packet = Packet(args)
880 packet.get_char() # skip ':' character
881 addr = packet.get_hex_uint('big')
882 print 'get_memory_region_info (addr=0x%x)' % (addr)
883
Greg Claytonf51a23f2012-06-04 23:22:17 +0000884def cmd_kill(options, cmd, args):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000885 print 'kill_process()'
886
887gdb_remote_commands = {
888 '\\?' : { 'cmd' : cmd_stop_reply , 'rsp' : rsp_stop_reply , 'name' : "stop reply pacpket"},
889 'QStartNoAckMode' : { 'cmd' : cmd_query_packet , 'rsp' : rsp_ok_means_supported , 'name' : "query if no ack mode is supported"},
890 'QThreadSuffixSupported' : { 'cmd' : cmd_query_packet , 'rsp' : rsp_ok_means_supported , 'name' : "query if thread suffix is supported" },
891 'QListThreadsInStopReply' : { 'cmd' : cmd_query_packet , 'rsp' : rsp_ok_means_supported , 'name' : "query if threads in stop reply packets are supported" },
Greg Clayton25f82aa2015-05-22 23:00:59 +0000892 'QSetDetachOnError' : { 'cmd' : cmd_query_packet , 'rsp' : rsp_ok_means_supported , 'name' : "query if we should detach on error" },
Greg Clayton48629002012-08-20 16:50:43 +0000893 'qVAttachOrWaitSupported' : { 'cmd' : cmd_query_packet , 'rsp' : rsp_ok_means_supported , 'name' : "query if threads attach with optional wait is supported" },
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000894 'qHostInfo' : { 'cmd' : cmd_query_packet , 'rsp' : rsp_dump_key_value_pairs, 'name' : "get host information" },
895 'vCont' : { 'cmd' : cmd_vCont , 'rsp' : rsp_vCont , 'name' : "extended continue command" },
896 'vAttach' : { 'cmd' : cmd_vAttach , 'rsp' : rsp_stop_reply , 'name' : "attach to process" },
897 'qRegisterInfo' : { 'cmd' : cmd_qRegisterInfo , 'rsp' : rsp_qRegisterInfo , 'name' : "query register info" },
898 'qfThreadInfo' : { 'cmd' : cmd_qThreadInfo , 'rsp' : rsp_qThreadInfo , 'name' : "get current thread list" },
899 'qsThreadInfo' : { 'cmd' : cmd_qThreadInfo , 'rsp' : rsp_qThreadInfo , 'name' : "get current thread list" },
900 'qShlibInfoAddr' : { 'cmd' : cmd_query_packet , 'rsp' : rsp_hex_big_endian , 'name' : "get shared library info address" },
901 'qMemoryRegionInfo' : { 'cmd' : cmd_mem_rgn_info , 'rsp' : rsp_dump_key_value_pairs, 'name' : "get memory region information" },
Greg Clayton25f82aa2015-05-22 23:00:59 +0000902 'qProcessInfo' : { 'cmd' : cmd_query_packet , 'rsp' : rsp_dump_key_value_pairs, 'name' : "get process info" },
903 'qSupported' : { 'cmd' : cmd_query_packet , 'rsp' : rsp_ok_means_supported , 'name' : "query supported" },
Greg Clayton374b6712015-07-02 22:22:45 +0000904 'qXfer:' : { 'cmd' : cmd_qXfer , 'rsp' : rsp_qXfer , 'name' : "qXfer" },
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000905 'm' : { 'cmd' : cmd_read_memory , 'rsp' : rsp_memory_bytes , 'name' : "read memory" },
906 'M' : { 'cmd' : cmd_write_memory , 'rsp' : rsp_ok_means_success , 'name' : "write memory" },
907 '_M' : { 'cmd' : cmd_alloc_memory , 'rsp' : rsp_alloc_memory , 'name' : "allocate memory" },
908 '_m' : { 'cmd' : cmd_dealloc_memory, 'rsp' : rsp_ok_means_success , 'name' : "deallocate memory" },
909 'p' : { 'cmd' : cmd_read_one_reg , 'rsp' : rsp_read_one_reg , 'name' : "read single register" },
910 'P' : { 'cmd' : cmd_write_one_reg , 'rsp' : rsp_ok_means_success , 'name' : "write single register" },
911 'g' : { 'cmd' : cmd_read_all_regs , 'rsp' : rsp_read_all_regs , 'name' : "read all registers" },
912 'G' : { 'cmd' : cmd_write_all_regs, 'rsp' : rsp_ok_means_success , 'name' : "write all registers" },
913 'z' : { 'cmd' : cmd_bp , 'rsp' : rsp_ok_means_success , 'name' : "clear breakpoint or watchpoint" },
914 'Z' : { 'cmd' : cmd_bp , 'rsp' : rsp_ok_means_success , 'name' : "set breakpoint or watchpoint" },
915 'k' : { 'cmd' : cmd_kill , 'rsp' : rsp_stop_reply , 'name' : "kill process" },
916}
Greg Clayton25f82aa2015-05-22 23:00:59 +0000917
918def calculate_mean_and_standard_deviation(floats):
919 sum = 0.0
920 count = len(floats)
921 for f in floats:
922 sum += f
923 mean = sum / count
924 accum = 0.0
925 for f in floats:
926 delta = f - mean
927 accum += delta * delta
928
929 std_dev = math.sqrt(accum / (count-1));
930 return (mean, std_dev)
931
Greg Claytone2841632012-01-26 02:56:24 +0000932def parse_gdb_log_file(file, options):
933 '''Parse a GDB log file that was generated by enabling logging with:
934 (lldb) log enable --threadsafe --timestamp --file <FILE> gdb-remote packets
Bruce Mitchenerd93c4a32014-07-01 21:22:11 +0000935 This log file will contain timestamps and this function will then normalize
Greg Claytone2841632012-01-26 02:56:24 +0000936 those packets to be relative to the first value timestamp that is found and
937 show delta times between log lines and also keep track of how long it takes
938 for GDB remote commands to make a send/receive round trip. This can be
939 handy when trying to figure out why some operation in the debugger is taking
940 a long time during a preset set of debugger commands.'''
941
942 tricky_commands = [ 'qRegisterInfo' ]
943 timestamp_regex = re.compile('(\s*)([1-9][0-9]+\.[0-9]+)([^0-9].*)$')
944 packet_name_regex = re.compile('([A-Za-z_]+)[^a-z]')
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000945 packet_transmit_name_regex = re.compile('(?P<direction>send|read) packet: (?P<packet>.*)')
946 packet_contents_name_regex = re.compile('\$([^#]+)#[0-9a-fA-F]{2}')
947 packet_names_regex_str = '(' + '|'.join(gdb_remote_commands.keys()) + ')(.*)';
948 packet_names_regex = re.compile(packet_names_regex_str);
949
Greg Claytone2841632012-01-26 02:56:24 +0000950 base_time = 0.0
951 last_time = 0.0
952 packet_send_time = 0.0
Greg Claytone2841632012-01-26 02:56:24 +0000953 packet_total_times = {}
Greg Clayton25f82aa2015-05-22 23:00:59 +0000954 packet_times = []
Jim Inghamd95752f2012-03-01 18:57:51 +0000955 packet_count = {}
Greg Claytone2841632012-01-26 02:56:24 +0000956 file = open(file)
957 lines = file.read().splitlines()
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000958 last_command = None
959 last_command_args = None
960 last_command_packet = None
Greg Claytone2841632012-01-26 02:56:24 +0000961 for line in lines:
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000962 m = packet_transmit_name_regex.search(line)
Greg Claytonf51a23f2012-06-04 23:22:17 +0000963 is_command = False
Greg Clayton25f82aa2015-05-22 23:00:59 +0000964 direction = None
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000965 if m:
966 direction = m.group('direction')
967 is_command = direction == 'send'
968 packet = m.group('packet')
Greg Claytonf51a23f2012-06-04 23:22:17 +0000969 sys.stdout.write(options.colors.green())
Greg Clayton25f82aa2015-05-22 23:00:59 +0000970 if not options.quiet:
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000971 print '# ', line
Greg Claytonf51a23f2012-06-04 23:22:17 +0000972 sys.stdout.write(options.colors.reset())
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000973
974 #print 'direction = "%s", packet = "%s"' % (direction, packet)
975
976 if packet[0] == '+':
Greg Clayton25f82aa2015-05-22 23:00:59 +0000977 if not options.quiet: print 'ACK'
978 continue
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000979 elif packet[0] == '-':
Greg Clayton25f82aa2015-05-22 23:00:59 +0000980 if not options.quiet: print 'NACK'
981 continue
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000982 elif packet[0] == '$':
983 m = packet_contents_name_regex.match(packet)
984 if m:
985 contents = m.group(1)
986 if is_command:
987 m = packet_names_regex.match (contents)
988 if m:
989 last_command = m.group(1)
Greg Claytonf51a23f2012-06-04 23:22:17 +0000990 packet_name = last_command
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000991 last_command_args = m.group(2)
992 last_command_packet = contents
Greg Claytonf51a23f2012-06-04 23:22:17 +0000993 gdb_remote_commands[last_command]['cmd'](options, last_command, last_command_args)
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000994 else:
Greg Clayton25f82aa2015-05-22 23:00:59 +0000995 packet_match = packet_name_regex.match (contents)
Greg Claytonf51a23f2012-06-04 23:22:17 +0000996 if packet_match:
997 packet_name = packet_match.group(1)
998 for tricky_cmd in tricky_commands:
999 if packet_name.find (tricky_cmd) == 0:
1000 packet_name = tricky_cmd
1001 else:
1002 packet_name = contents
Greg Clayton8ebb9a82012-06-01 20:23:54 +00001003 last_command = None
1004 last_command_args = None
1005 last_command_packet = None
1006 elif last_command:
Greg Claytonf51a23f2012-06-04 23:22:17 +00001007 gdb_remote_commands[last_command]['rsp'](options, last_command, last_command_args, contents)
Greg Clayton8ebb9a82012-06-01 20:23:54 +00001008 else:
1009 print 'error: invalid packet: "', packet, '"'
1010 else:
1011 print '???'
1012 else:
1013 print '## ', line
Greg Claytone2841632012-01-26 02:56:24 +00001014 match = timestamp_regex.match (line)
1015 if match:
1016 curr_time = float (match.group(2))
Greg Clayton25f82aa2015-05-22 23:00:59 +00001017 if last_time and not is_command:
1018 delta = curr_time - last_time
1019 packet_times.append(delta)
Greg Claytone2841632012-01-26 02:56:24 +00001020 delta = 0.0
1021 if base_time:
1022 delta = curr_time - last_time
1023 else:
1024 base_time = curr_time
Greg Claytonf51a23f2012-06-04 23:22:17 +00001025
1026 if is_command:
Greg Claytone2841632012-01-26 02:56:24 +00001027 packet_send_time = curr_time
Greg Claytone2841632012-01-26 02:56:24 +00001028 elif line.find('read packet: $') >= 0 and packet_name:
1029 if packet_name in packet_total_times:
1030 packet_total_times[packet_name] += delta
Jim Inghamd95752f2012-03-01 18:57:51 +00001031 packet_count[packet_name] += 1
Greg Claytone2841632012-01-26 02:56:24 +00001032 else:
1033 packet_total_times[packet_name] = delta
Jim Inghamd95752f2012-03-01 18:57:51 +00001034 packet_count[packet_name] = 1
Greg Claytone2841632012-01-26 02:56:24 +00001035 packet_name = None
1036
1037 if not options or not options.quiet:
1038 print '%s%.6f %+.6f%s' % (match.group(1), curr_time - base_time, delta, match.group(3))
1039 last_time = curr_time
Greg Clayton8ebb9a82012-06-01 20:23:54 +00001040 # else:
1041 # print line
Greg Clayton25f82aa2015-05-22 23:00:59 +00001042 (average, std_dev) = calculate_mean_and_standard_deviation(packet_times)
1043 print '%u packets with average packet time of %f and standard deviation of %f' % (len(packet_times), average, std_dev)
Greg Claytone2841632012-01-26 02:56:24 +00001044 if packet_total_times:
1045 total_packet_time = 0.0
Jim Inghamd95752f2012-03-01 18:57:51 +00001046 total_packet_count = 0
Greg Claytone2841632012-01-26 02:56:24 +00001047 for key, vvv in packet_total_times.items():
1048 # print ' key = (%s) "%s"' % (type(key), key)
1049 # print 'value = (%s) %s' % (type(vvv), vvv)
1050 # if type(vvv) == 'float':
1051 total_packet_time += vvv
Jim Inghamd95752f2012-03-01 18:57:51 +00001052 for key, vvv in packet_count.items():
1053 total_packet_count += vvv
1054
1055 print '#---------------------------------------------------'
Greg Claytone2841632012-01-26 02:56:24 +00001056 print '# Packet timing summary:'
Greg Clayton25f82aa2015-05-22 23:00:59 +00001057 print '# Totals: time = %6f, count = %6d' % (total_packet_time, total_packet_count)
Jim Inghamd95752f2012-03-01 18:57:51 +00001058 print '#---------------------------------------------------'
1059 print '# Packet Time (sec) Percent Count '
1060 print '#------------------------- ---------- ------- ------'
1061 if options and options.sort_count:
1062 res = sorted(packet_count, key=packet_count.__getitem__, reverse=True)
1063 else:
1064 res = sorted(packet_total_times, key=packet_total_times.__getitem__, reverse=True)
1065
Greg Claytone2841632012-01-26 02:56:24 +00001066 if last_time > 0.0:
1067 for item in res:
1068 packet_total_time = packet_total_times[item]
1069 packet_percent = (packet_total_time / total_packet_time)*100.0
1070 if packet_percent >= 10.0:
Jim Inghamd95752f2012-03-01 18:57:51 +00001071 print " %24s %.6f %.2f%% %6d" % (item, packet_total_time, packet_percent, packet_count[item])
Greg Claytone2841632012-01-26 02:56:24 +00001072 else:
Jim Inghamd95752f2012-03-01 18:57:51 +00001073 print " %24s %.6f %.2f%% %6d" % (item, packet_total_time, packet_percent, packet_count[item])
Greg Claytone2841632012-01-26 02:56:24 +00001074
1075
1076
1077if __name__ == '__main__':
Greg Clayton8ebb9a82012-06-01 20:23:54 +00001078 usage = "usage: gdbremote [options]"
1079 description='''The command disassembles a GDB remote packet log.'''
1080 parser = optparse.OptionParser(description=description, prog='gdbremote',usage=usage)
1081 parser.add_option('-v', '--verbose', action='store_true', dest='verbose', help='display verbose debug info', default=False)
1082 parser.add_option('-q', '--quiet', action='store_true', dest='quiet', help='display verbose debug info', default=False)
1083 parser.add_option('-C', '--color', action='store_true', dest='color', help='add terminal colors', default=False)
1084 parser.add_option('-c', '--sort-by-count', action='store_true', dest='sort_count', help='display verbose debug info', default=False)
Greg Claytonf51a23f2012-06-04 23:22:17 +00001085 parser.add_option('--crashlog', type='string', dest='crashlog', help='symbolicate using a darwin crash log file', default=False)
Greg Clayton8ebb9a82012-06-01 20:23:54 +00001086 try:
1087 (options, args) = parser.parse_args(sys.argv[1:])
1088 except:
1089 print 'error: argument error'
1090 sys.exit(1)
1091
Greg Claytonf51a23f2012-06-04 23:22:17 +00001092 options.colors = TerminalColors(options.color)
1093 options.symbolicator = None
1094 if options.crashlog:
1095 import lldb
1096 lldb.debugger = lldb.SBDebugger.Create()
1097 import lldb.macosx.crashlog
1098 options.symbolicator = lldb.macosx.crashlog.CrashLog(options.crashlog)
1099 print '%s' % (options.symbolicator)
Greg Clayton8ebb9a82012-06-01 20:23:54 +00001100
Greg Claytone2841632012-01-26 02:56:24 +00001101 # This script is being run from the command line, create a debugger in case we are
1102 # going to use any debugger functions in our function.
Greg Clayton8ebb9a82012-06-01 20:23:54 +00001103 for file in args:
Greg Claytone2841632012-01-26 02:56:24 +00001104 print '#----------------------------------------------------------------------'
1105 print "# GDB remote log file: '%s'" % file
1106 print '#----------------------------------------------------------------------'
Greg Clayton8ebb9a82012-06-01 20:23:54 +00001107 parse_gdb_log_file (file, options)
Greg Claytonf51a23f2012-06-04 23:22:17 +00001108 if options.symbolicator:
1109 print '%s' % (options.symbolicator)
1110
Greg Claytone2841632012-01-26 02:56:24 +00001111else:
1112 import lldb
1113 if lldb.debugger:
1114 # This initializer is being run from LLDB in the embedded command interpreter
1115 # Add any commands contained in this module to LLDB
1116 lldb.debugger.HandleCommand('command script add -f gdbremote.start_gdb_log start_gdb_log')
1117 lldb.debugger.HandleCommand('command script add -f gdbremote.stop_gdb_log stop_gdb_log')
1118 print 'The "start_gdb_log" and "stop_gdb_log" commands are now installed and ready for use, type "start_gdb_log --help" or "stop_gdb_log --help" for more information'