blob: c4b1c1d60d51a71fa0eb078a67b3d4418d4ebf57 [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])
Greg Claytonb2273bd2015-07-17 00:19:31 +0000498 elif key == 'jthreads' or key == 'jstopinfo':
499 key_value_pair[1] = binascii.unhexlify(key_value_pair[1])
Greg Clayton374b6712015-07-02 22:22:45 +0000500 key_value_pairs.insert(0, ['signal', signo])
501 dump_key_value_pairs (key_value_pairs)
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000502 elif stop_type == 'W':
503 exit_status = packet.get_hex_uint8()
504 print 'exit (status=%i)' % exit_status
505 elif stop_type == 'O':
506 print 'stdout = %s' % packet.str
507
508
Greg Claytonf51a23f2012-06-04 23:22:17 +0000509def cmd_unknown_packet(options, cmd, args):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000510 if args:
511 print "cmd: %s, args: %s", cmd, args
512 else:
513 print "cmd: %s", cmd
514
Greg Clayton374b6712015-07-02 22:22:45 +0000515def cmd_qXfer(options, cmd, args):
516 # $qXfer:features:read:target.xml:0,1ffff#14
517 print "read target special data %s" % (args)
518
519def rsp_qXfer(options, cmd, cmd_args, rsp):
520 data = string.split(cmd_args, ':')
521 if data[0] == 'features':
522 if data[1] == 'read':
523 filename, extension = os.path.splitext(data[2])
524 if extension == '.xml':
525 response = Packet(rsp)
526 xml_string = response.get_hex_ascii_str()
527 ch = xml_string[0]
528 if ch == 'l':
529 xml_string = xml_string[1:]
530 xml_root = ET.fromstring(xml_string)
531 for reg_element in xml_root.findall("./feature/reg"):
532 if not 'value_regnums' in reg_element.attrib:
533 reg_info = RegisterInfo([])
534 if 'name' in reg_element.attrib:
535 reg_info.info['name'] = reg_element.attrib['name']
536 else:
537 reg_info.info['name'] = 'unspecified'
538 if 'encoding' in reg_element.attrib:
539 reg_info.info['encoding'] = reg_element.attrib['encoding']
540 else:
541 reg_info.info['encoding'] = 'uint'
542 if 'offset' in reg_element.attrib:
543 reg_info.info['offset'] = reg_element.attrib['offset']
544 if 'bitsize' in reg_element.attrib:
545 reg_info.info['bitsize'] = reg_element.attrib['bitsize']
546 g_register_infos.append(reg_info)
547
548
Greg Claytonf51a23f2012-06-04 23:22:17 +0000549def cmd_query_packet(options, cmd, args):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000550 if args:
Greg Claytonf51a23f2012-06-04 23:22:17 +0000551 print "query: %s, args: %s" % (cmd, args)
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000552 else:
Greg Claytonf51a23f2012-06-04 23:22:17 +0000553 print "query: %s" % (cmd)
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000554
555def rsp_ok_error(rsp):
556 print "rsp: ", rsp
557
Greg Claytonf51a23f2012-06-04 23:22:17 +0000558def rsp_ok_means_supported(options, cmd, cmd_args, rsp):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000559 if rsp == 'OK':
560 print "%s%s is supported" % (cmd, cmd_args)
561 elif rsp == '':
562 print "%s%s is not supported" % (cmd, cmd_args)
563 else:
564 print "%s%s -> %s" % (cmd, cmd_args, rsp)
565
Greg Claytonf51a23f2012-06-04 23:22:17 +0000566def rsp_ok_means_success(options, cmd, cmd_args, rsp):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000567 if rsp == 'OK':
568 print "success"
569 elif rsp == '':
570 print "%s%s is not supported" % (cmd, cmd_args)
571 else:
572 print "%s%s -> %s" % (cmd, cmd_args, rsp)
573
Greg Clayton374b6712015-07-02 22:22:45 +0000574def dump_key_value_pairs(key_value_pairs):
575 max_key_len = 0
576 for key_value_pair in key_value_pairs:
577 key_len = len(key_value_pair[0])
578 if max_key_len < key_len:
579 max_key_len = key_len
580 for key_value_pair in key_value_pairs:
581 key = key_value_pair[0]
582 value = key_value_pair[1]
583 print "%*s = %s" % (max_key_len, key, value)
584
Greg Claytonf51a23f2012-06-04 23:22:17 +0000585def rsp_dump_key_value_pairs(options, cmd, cmd_args, rsp):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000586 if rsp:
587 packet = Packet(rsp)
588 key_value_pairs = packet.get_key_value_pairs()
Greg Clayton374b6712015-07-02 22:22:45 +0000589 dump_key_value_pairs(key_value_pairs)
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000590 else:
591 print "not supported"
592
Greg Claytonb2273bd2015-07-17 00:19:31 +0000593def cmd_c(options, cmd, args):
594 print "continue()"
595
596def cmd_s(options, cmd, args):
597 print "step()"
598
Greg Claytonf51a23f2012-06-04 23:22:17 +0000599def cmd_vCont(options, cmd, args):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000600 if args == '?':
601 print "%s: get supported extended continue modes" % (cmd)
602 else:
603 got_other_threads = 0
604 s = ''
605 for thread_action in string.split(args[1:], ';'):
606 (short_action, thread) = string.split(thread_action, ':')
607 tid = int(thread, 16)
608 if short_action == 'c':
609 action = 'continue'
610 elif short_action == 's':
611 action = 'step'
612 elif short_action[0] == 'C':
613 action = 'continue with signal 0x%s' % (short_action[1:])
614 elif short_action == 'S':
615 action = 'step with signal 0x%s' % (short_action[1:])
616 else:
617 action = short_action
618 if s:
619 s += ', '
620 if tid == -1:
621 got_other_threads = 1
622 s += 'other-threads:'
623 else:
624 s += 'thread 0x%4.4x: %s' % (tid, action)
625 if got_other_threads:
626 print "extended_continue (%s)" % (s)
627 else:
628 print "extended_continue (%s, other-threads: suspend)" % (s)
629
Greg Claytonf51a23f2012-06-04 23:22:17 +0000630def rsp_vCont(options, cmd, cmd_args, rsp):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000631 if cmd_args == '?':
632 # Skip the leading 'vCont;'
633 rsp = rsp[6:]
634 modes = string.split(rsp, ';')
635 s = "%s: supported extended continue modes include: " % (cmd)
636
637 for i, mode in enumerate(modes):
638 if i:
639 s += ', '
640 if mode == 'c':
641 s += 'continue'
642 elif mode == 'C':
643 s += 'continue with signal'
644 elif mode == 's':
645 s += 'step'
646 elif mode == 'S':
647 s += 'step with signal'
648 else:
649 s += 'unrecognized vCont mode: ', mode
650 print s
651 elif rsp:
652 if rsp[0] == 'T' or rsp[0] == 'S' or rsp[0] == 'W' or rsp[0] == 'X':
Greg Claytonf51a23f2012-06-04 23:22:17 +0000653 rsp_stop_reply (options, cmd, cmd_args, rsp)
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000654 return
655 if rsp[0] == 'O':
656 print "stdout: %s" % (rsp)
657 return
658 else:
659 print "not supported (cmd = '%s', args = '%s', rsp = '%s')" % (cmd, cmd_args, rsp)
660
Greg Claytonf51a23f2012-06-04 23:22:17 +0000661def cmd_vAttach(options, cmd, args):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000662 (extra_command, args) = string.split(args, ';')
663 if extra_command:
664 print "%s%s(%s)" % (cmd, extra_command, args)
665 else:
666 print "attach_pid(%s)" % args
667
Greg Claytonf51a23f2012-06-04 23:22:17 +0000668def cmd_qRegisterInfo(options, cmd, args):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000669 print 'query_register_info(reg_num=%i)' % (int(args, 16))
670
Greg Claytonf51a23f2012-06-04 23:22:17 +0000671def rsp_qRegisterInfo(options, cmd, cmd_args, rsp):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000672 global g_max_register_info_name_len
673 print 'query_register_info(reg_num=%i):' % (int(cmd_args, 16)),
674 if len(rsp) == 3 and rsp[0] == 'E':
675 g_max_register_info_name_len = 0
676 for reg_info in g_register_infos:
677 name_len = len(reg_info.name())
678 if g_max_register_info_name_len < name_len:
679 g_max_register_info_name_len = name_len
680 print' DONE'
681 else:
682 packet = Packet(rsp)
683 reg_info = RegisterInfo(packet.get_key_value_pairs())
684 g_register_infos.append(reg_info)
685 print reg_info
686
687
Greg Claytonf51a23f2012-06-04 23:22:17 +0000688def cmd_qThreadInfo(options, cmd, args):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000689 if cmd == 'qfThreadInfo':
690 query_type = 'first'
691 else:
692 query_type = 'subsequent'
693 print 'get_current_thread_list(type=%s)' % (query_type)
694
Greg Claytonf51a23f2012-06-04 23:22:17 +0000695def rsp_qThreadInfo(options, cmd, cmd_args, rsp):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000696 packet = Packet(rsp)
697 response_type = packet.get_char()
698 if response_type == 'm':
699 tids = packet.split_hex(';', 'big')
700 for i, tid in enumerate(tids):
701 if i:
702 print ',',
703 print '0x%x' % (tid),
704 print
705 elif response_type == 'l':
706 print 'END'
707
Greg Claytonf51a23f2012-06-04 23:22:17 +0000708def rsp_hex_big_endian(options, cmd, cmd_args, rsp):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000709 packet = Packet(rsp)
710 uval = packet.get_hex_uint('big')
711 print '%s: 0x%x' % (cmd, uval)
712
Greg Claytonf51a23f2012-06-04 23:22:17 +0000713def cmd_read_memory(options, cmd, args):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000714 packet = Packet(args)
715 addr = packet.get_hex_uint('big')
716 comma = packet.get_char()
717 size = packet.get_hex_uint('big')
718 print 'read_memory (addr = 0x%x, size = %u)' % (addr, size)
719
720def dump_hex_memory_buffer(addr, hex_byte_str):
721 packet = Packet(hex_byte_str)
722 idx = 0
723 ascii = ''
724 uval = packet.get_hex_uint8()
725 while uval != None:
726 if ((idx % 16) == 0):
727 if ascii:
728 print ' ', ascii
729 ascii = ''
730 print '0x%x:' % (addr + idx),
731 print '%2.2x' % (uval),
732 if 0x20 <= uval and uval < 0x7f:
733 ascii += '%c' % uval
734 else:
735 ascii += '.'
736 uval = packet.get_hex_uint8()
737 idx = idx + 1
738 if ascii:
739 print ' ', ascii
740 ascii = ''
741
Greg Claytonf51a23f2012-06-04 23:22:17 +0000742def cmd_write_memory(options, cmd, args):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000743 packet = Packet(args)
744 addr = packet.get_hex_uint('big')
745 if packet.get_char() != ',':
746 print 'error: invalid write memory command (missing comma after address)'
747 return
748 size = packet.get_hex_uint('big')
749 if packet.get_char() != ':':
750 print 'error: invalid write memory command (missing colon after size)'
751 return
752 print 'write_memory (addr = 0x%x, size = %u, data:' % (addr, size)
753 dump_hex_memory_buffer (addr, packet.str)
754
Greg Claytonf51a23f2012-06-04 23:22:17 +0000755def cmd_alloc_memory(options, cmd, args):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000756 packet = Packet(args)
757 byte_size = packet.get_hex_uint('big')
758 if packet.get_char() != ',':
759 print 'error: invalid allocate memory command (missing comma after address)'
760 return
761 print 'allocate_memory (byte-size = %u (0x%x), permissions = %s)' % (byte_size, byte_size, packet.str)
762
Greg Claytonf51a23f2012-06-04 23:22:17 +0000763def rsp_alloc_memory(options, cmd, cmd_args, rsp):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000764 packet = Packet(rsp)
765 addr = packet.get_hex_uint('big')
766 print 'addr = 0x%x' % addr
767
Greg Claytonf51a23f2012-06-04 23:22:17 +0000768def cmd_dealloc_memory(options, cmd, args):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000769 packet = Packet(args)
770 addr = packet.get_hex_uint('big')
771 if packet.get_char() != ',':
772 print 'error: invalid allocate memory command (missing comma after address)'
773 return
774 print 'deallocate_memory (addr = 0x%x, permissions = %s)' % (addr, packet.str)
775
Greg Claytonf51a23f2012-06-04 23:22:17 +0000776def rsp_memory_bytes(options, cmd, cmd_args, rsp):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000777 addr = Packet(cmd_args).get_hex_uint('big')
778 dump_hex_memory_buffer (addr, rsp)
779
Greg Claytonf51a23f2012-06-04 23:22:17 +0000780def get_register_name_equal_value(options, reg_num, hex_value_str):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000781 if reg_num < len(g_register_infos):
782 reg_info = g_register_infos[reg_num]
Greg Claytonf51a23f2012-06-04 23:22:17 +0000783 value_str = reg_info.get_value_from_hex_string (hex_value_str)
784 s = reg_info.name() + ' = '
785 if options.symbolicator:
786 symbolicated_addresses = options.symbolicator.symbolicate (int(value_str, 0))
787 if symbolicated_addresses:
788 s += options.colors.magenta()
789 s += '%s' % symbolicated_addresses[0]
790 s += options.colors.reset()
791 return s
792 s += value_str
793 return s
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000794 else:
795 reg_value = Packet(hex_value_str).get_hex_uint(g_byte_order)
796 return 'reg(%u) = 0x%x' % (reg_num, reg_value)
797
Greg Claytonf51a23f2012-06-04 23:22:17 +0000798def cmd_read_one_reg(options, cmd, args):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000799 packet = Packet(args)
800 reg_num = packet.get_hex_uint('big')
801 tid = get_thread_from_thread_suffix (packet.str)
802 name = None
803 if reg_num < len(g_register_infos):
804 name = g_register_infos[reg_num].name ()
805 if packet.str:
806 packet.get_char() # skip ;
807 thread_info = packet.get_key_value_pairs()
808 tid = int(thread_info[0][1], 16)
809 s = 'read_register (reg_num=%u' % reg_num
810 if name:
811 s += ' (%s)' % (name)
812 if tid != None:
813 s += ', tid = 0x%4.4x' % (tid)
814 s += ')'
815 print s
816
Greg Claytonf51a23f2012-06-04 23:22:17 +0000817def rsp_read_one_reg(options, cmd, cmd_args, rsp):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000818 packet = Packet(cmd_args)
819 reg_num = packet.get_hex_uint('big')
Greg Claytonf51a23f2012-06-04 23:22:17 +0000820 print get_register_name_equal_value (options, reg_num, rsp)
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000821
Greg Claytonf51a23f2012-06-04 23:22:17 +0000822def cmd_write_one_reg(options, cmd, args):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000823 packet = Packet(args)
824 reg_num = packet.get_hex_uint('big')
825 if packet.get_char() != '=':
826 print 'error: invalid register write packet'
827 else:
828 name = None
829 hex_value_str = packet.get_hex_chars()
830 tid = get_thread_from_thread_suffix (packet.str)
831 s = 'write_register (reg_num=%u' % reg_num
832 if name:
833 s += ' (%s)' % (name)
834 s += ', value = '
Greg Claytonf51a23f2012-06-04 23:22:17 +0000835 s += get_register_name_equal_value(options, reg_num, hex_value_str)
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000836 if tid != None:
837 s += ', tid = 0x%4.4x' % (tid)
838 s += ')'
839 print s
840
841def dump_all_regs(packet):
842 for reg_info in g_register_infos:
843 nibble_size = reg_info.bit_size() / 4
844 hex_value_str = packet.get_hex_chars(nibble_size)
845 if hex_value_str != None:
846 value = reg_info.get_value_from_hex_string (hex_value_str)
847 print '%*s = %s' % (g_max_register_info_name_len, reg_info.name(), value)
848 else:
849 return
850
851def cmd_read_all_regs(cmd, cmd_args):
852 packet = Packet(cmd_args)
853 packet.get_char() # toss the 'g' command character
854 tid = get_thread_from_thread_suffix (packet.str)
855 if tid != None:
856 print 'read_all_register(thread = 0x%4.4x)' % tid
857 else:
858 print 'read_all_register()'
859
Greg Claytonf51a23f2012-06-04 23:22:17 +0000860def rsp_read_all_regs(options, cmd, cmd_args, rsp):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000861 packet = Packet(rsp)
862 dump_all_regs (packet)
863
Greg Claytonf51a23f2012-06-04 23:22:17 +0000864def cmd_write_all_regs(options, cmd, args):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000865 packet = Packet(args)
866 print 'write_all_registers()'
867 dump_all_regs (packet)
868
869g_bp_types = [ "software_bp", "hardware_bp", "write_wp", "read_wp", "access_wp" ]
870
Greg Claytonf51a23f2012-06-04 23:22:17 +0000871def cmd_bp(options, cmd, args):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000872 if cmd == 'Z':
873 s = 'set_'
874 else:
875 s = 'clear_'
876 packet = Packet (args)
877 bp_type = packet.get_hex_uint('big')
878 packet.get_char() # Skip ,
879 bp_addr = packet.get_hex_uint('big')
880 packet.get_char() # Skip ,
881 bp_size = packet.get_hex_uint('big')
882 s += g_bp_types[bp_type]
883 s += " (addr = 0x%x, size = %u)" % (bp_addr, bp_size)
884 print s
885
Greg Claytonf51a23f2012-06-04 23:22:17 +0000886def cmd_mem_rgn_info(options, cmd, args):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000887 packet = Packet(args)
888 packet.get_char() # skip ':' character
889 addr = packet.get_hex_uint('big')
890 print 'get_memory_region_info (addr=0x%x)' % (addr)
891
Greg Claytonf51a23f2012-06-04 23:22:17 +0000892def cmd_kill(options, cmd, args):
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000893 print 'kill_process()'
894
895gdb_remote_commands = {
896 '\\?' : { 'cmd' : cmd_stop_reply , 'rsp' : rsp_stop_reply , 'name' : "stop reply pacpket"},
897 'QStartNoAckMode' : { 'cmd' : cmd_query_packet , 'rsp' : rsp_ok_means_supported , 'name' : "query if no ack mode is supported"},
898 'QThreadSuffixSupported' : { 'cmd' : cmd_query_packet , 'rsp' : rsp_ok_means_supported , 'name' : "query if thread suffix is supported" },
899 '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 +0000900 '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 +0000901 '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 +0000902 'qHostInfo' : { 'cmd' : cmd_query_packet , 'rsp' : rsp_dump_key_value_pairs, 'name' : "get host information" },
903 'vCont' : { 'cmd' : cmd_vCont , 'rsp' : rsp_vCont , 'name' : "extended continue command" },
904 'vAttach' : { 'cmd' : cmd_vAttach , 'rsp' : rsp_stop_reply , 'name' : "attach to process" },
Greg Claytonb2273bd2015-07-17 00:19:31 +0000905 'c' : { 'cmd' : cmd_c , 'rsp' : rsp_stop_reply , 'name' : "continue" },
906 's' : { 'cmd' : cmd_s , 'rsp' : rsp_stop_reply , 'name' : "step" },
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000907 'qRegisterInfo' : { 'cmd' : cmd_qRegisterInfo , 'rsp' : rsp_qRegisterInfo , 'name' : "query register info" },
908 'qfThreadInfo' : { 'cmd' : cmd_qThreadInfo , 'rsp' : rsp_qThreadInfo , 'name' : "get current thread list" },
909 'qsThreadInfo' : { 'cmd' : cmd_qThreadInfo , 'rsp' : rsp_qThreadInfo , 'name' : "get current thread list" },
910 'qShlibInfoAddr' : { 'cmd' : cmd_query_packet , 'rsp' : rsp_hex_big_endian , 'name' : "get shared library info address" },
911 'qMemoryRegionInfo' : { 'cmd' : cmd_mem_rgn_info , 'rsp' : rsp_dump_key_value_pairs, 'name' : "get memory region information" },
Greg Clayton25f82aa2015-05-22 23:00:59 +0000912 'qProcessInfo' : { 'cmd' : cmd_query_packet , 'rsp' : rsp_dump_key_value_pairs, 'name' : "get process info" },
913 'qSupported' : { 'cmd' : cmd_query_packet , 'rsp' : rsp_ok_means_supported , 'name' : "query supported" },
Greg Clayton374b6712015-07-02 22:22:45 +0000914 'qXfer:' : { 'cmd' : cmd_qXfer , 'rsp' : rsp_qXfer , 'name' : "qXfer" },
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000915 'm' : { 'cmd' : cmd_read_memory , 'rsp' : rsp_memory_bytes , 'name' : "read memory" },
916 'M' : { 'cmd' : cmd_write_memory , 'rsp' : rsp_ok_means_success , 'name' : "write memory" },
917 '_M' : { 'cmd' : cmd_alloc_memory , 'rsp' : rsp_alloc_memory , 'name' : "allocate memory" },
918 '_m' : { 'cmd' : cmd_dealloc_memory, 'rsp' : rsp_ok_means_success , 'name' : "deallocate memory" },
919 'p' : { 'cmd' : cmd_read_one_reg , 'rsp' : rsp_read_one_reg , 'name' : "read single register" },
920 'P' : { 'cmd' : cmd_write_one_reg , 'rsp' : rsp_ok_means_success , 'name' : "write single register" },
921 'g' : { 'cmd' : cmd_read_all_regs , 'rsp' : rsp_read_all_regs , 'name' : "read all registers" },
922 'G' : { 'cmd' : cmd_write_all_regs, 'rsp' : rsp_ok_means_success , 'name' : "write all registers" },
923 'z' : { 'cmd' : cmd_bp , 'rsp' : rsp_ok_means_success , 'name' : "clear breakpoint or watchpoint" },
924 'Z' : { 'cmd' : cmd_bp , 'rsp' : rsp_ok_means_success , 'name' : "set breakpoint or watchpoint" },
925 'k' : { 'cmd' : cmd_kill , 'rsp' : rsp_stop_reply , 'name' : "kill process" },
926}
Greg Clayton25f82aa2015-05-22 23:00:59 +0000927
928def calculate_mean_and_standard_deviation(floats):
929 sum = 0.0
930 count = len(floats)
Greg Claytonb2273bd2015-07-17 00:19:31 +0000931 if count == 0:
932 return (0.0, 0.0)
Greg Clayton25f82aa2015-05-22 23:00:59 +0000933 for f in floats:
934 sum += f
935 mean = sum / count
936 accum = 0.0
937 for f in floats:
938 delta = f - mean
939 accum += delta * delta
940
941 std_dev = math.sqrt(accum / (count-1));
942 return (mean, std_dev)
Greg Claytonb2273bd2015-07-17 00:19:31 +0000943
944def parse_gdb_log_file(path, options):
945 f = open(path)
946 parse_gdb_log(f)
947 f.close()
Greg Clayton25f82aa2015-05-22 23:00:59 +0000948
Greg Claytonb2273bd2015-07-17 00:19:31 +0000949def parse_gdb_log(file, options):
Greg Claytone2841632012-01-26 02:56:24 +0000950 '''Parse a GDB log file that was generated by enabling logging with:
951 (lldb) log enable --threadsafe --timestamp --file <FILE> gdb-remote packets
Bruce Mitchenerd93c4a32014-07-01 21:22:11 +0000952 This log file will contain timestamps and this function will then normalize
Greg Claytone2841632012-01-26 02:56:24 +0000953 those packets to be relative to the first value timestamp that is found and
954 show delta times between log lines and also keep track of how long it takes
955 for GDB remote commands to make a send/receive round trip. This can be
956 handy when trying to figure out why some operation in the debugger is taking
957 a long time during a preset set of debugger commands.'''
958
959 tricky_commands = [ 'qRegisterInfo' ]
960 timestamp_regex = re.compile('(\s*)([1-9][0-9]+\.[0-9]+)([^0-9].*)$')
961 packet_name_regex = re.compile('([A-Za-z_]+)[^a-z]')
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000962 packet_transmit_name_regex = re.compile('(?P<direction>send|read) packet: (?P<packet>.*)')
963 packet_contents_name_regex = re.compile('\$([^#]+)#[0-9a-fA-F]{2}')
964 packet_names_regex_str = '(' + '|'.join(gdb_remote_commands.keys()) + ')(.*)';
965 packet_names_regex = re.compile(packet_names_regex_str);
966
Greg Claytone2841632012-01-26 02:56:24 +0000967 base_time = 0.0
968 last_time = 0.0
969 packet_send_time = 0.0
Greg Claytone2841632012-01-26 02:56:24 +0000970 packet_total_times = {}
Greg Clayton25f82aa2015-05-22 23:00:59 +0000971 packet_times = []
Jim Inghamd95752f2012-03-01 18:57:51 +0000972 packet_count = {}
Greg Claytone2841632012-01-26 02:56:24 +0000973 lines = file.read().splitlines()
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000974 last_command = None
975 last_command_args = None
976 last_command_packet = None
Greg Claytone2841632012-01-26 02:56:24 +0000977 for line in lines:
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000978 m = packet_transmit_name_regex.search(line)
Greg Claytonf51a23f2012-06-04 23:22:17 +0000979 is_command = False
Greg Clayton25f82aa2015-05-22 23:00:59 +0000980 direction = None
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000981 if m:
982 direction = m.group('direction')
983 is_command = direction == 'send'
984 packet = m.group('packet')
Greg Claytonf51a23f2012-06-04 23:22:17 +0000985 sys.stdout.write(options.colors.green())
Greg Clayton25f82aa2015-05-22 23:00:59 +0000986 if not options.quiet:
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000987 print '# ', line
Greg Claytonf51a23f2012-06-04 23:22:17 +0000988 sys.stdout.write(options.colors.reset())
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000989
990 #print 'direction = "%s", packet = "%s"' % (direction, packet)
991
992 if packet[0] == '+':
Greg Clayton25f82aa2015-05-22 23:00:59 +0000993 if not options.quiet: print 'ACK'
994 continue
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000995 elif packet[0] == '-':
Greg Clayton25f82aa2015-05-22 23:00:59 +0000996 if not options.quiet: print 'NACK'
997 continue
Greg Clayton8ebb9a82012-06-01 20:23:54 +0000998 elif packet[0] == '$':
999 m = packet_contents_name_regex.match(packet)
1000 if m:
1001 contents = m.group(1)
1002 if is_command:
1003 m = packet_names_regex.match (contents)
1004 if m:
1005 last_command = m.group(1)
Greg Claytonf51a23f2012-06-04 23:22:17 +00001006 packet_name = last_command
Greg Clayton8ebb9a82012-06-01 20:23:54 +00001007 last_command_args = m.group(2)
1008 last_command_packet = contents
Greg Claytonf51a23f2012-06-04 23:22:17 +00001009 gdb_remote_commands[last_command]['cmd'](options, last_command, last_command_args)
Greg Clayton8ebb9a82012-06-01 20:23:54 +00001010 else:
Greg Clayton25f82aa2015-05-22 23:00:59 +00001011 packet_match = packet_name_regex.match (contents)
Greg Claytonf51a23f2012-06-04 23:22:17 +00001012 if packet_match:
1013 packet_name = packet_match.group(1)
1014 for tricky_cmd in tricky_commands:
1015 if packet_name.find (tricky_cmd) == 0:
1016 packet_name = tricky_cmd
1017 else:
1018 packet_name = contents
Greg Clayton8ebb9a82012-06-01 20:23:54 +00001019 last_command = None
1020 last_command_args = None
1021 last_command_packet = None
1022 elif last_command:
Greg Claytonf51a23f2012-06-04 23:22:17 +00001023 gdb_remote_commands[last_command]['rsp'](options, last_command, last_command_args, contents)
Greg Clayton8ebb9a82012-06-01 20:23:54 +00001024 else:
1025 print 'error: invalid packet: "', packet, '"'
1026 else:
1027 print '???'
1028 else:
1029 print '## ', line
Greg Claytone2841632012-01-26 02:56:24 +00001030 match = timestamp_regex.match (line)
1031 if match:
1032 curr_time = float (match.group(2))
Greg Clayton25f82aa2015-05-22 23:00:59 +00001033 if last_time and not is_command:
1034 delta = curr_time - last_time
1035 packet_times.append(delta)
Greg Claytone2841632012-01-26 02:56:24 +00001036 delta = 0.0
1037 if base_time:
1038 delta = curr_time - last_time
1039 else:
1040 base_time = curr_time
Greg Claytonf51a23f2012-06-04 23:22:17 +00001041
1042 if is_command:
Greg Claytone2841632012-01-26 02:56:24 +00001043 packet_send_time = curr_time
Greg Claytone2841632012-01-26 02:56:24 +00001044 elif line.find('read packet: $') >= 0 and packet_name:
1045 if packet_name in packet_total_times:
1046 packet_total_times[packet_name] += delta
Jim Inghamd95752f2012-03-01 18:57:51 +00001047 packet_count[packet_name] += 1
Greg Claytone2841632012-01-26 02:56:24 +00001048 else:
1049 packet_total_times[packet_name] = delta
Jim Inghamd95752f2012-03-01 18:57:51 +00001050 packet_count[packet_name] = 1
Greg Claytone2841632012-01-26 02:56:24 +00001051 packet_name = None
1052
1053 if not options or not options.quiet:
1054 print '%s%.6f %+.6f%s' % (match.group(1), curr_time - base_time, delta, match.group(3))
1055 last_time = curr_time
Greg Clayton8ebb9a82012-06-01 20:23:54 +00001056 # else:
1057 # print line
Greg Clayton25f82aa2015-05-22 23:00:59 +00001058 (average, std_dev) = calculate_mean_and_standard_deviation(packet_times)
1059 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 +00001060 if packet_total_times:
1061 total_packet_time = 0.0
Jim Inghamd95752f2012-03-01 18:57:51 +00001062 total_packet_count = 0
Greg Claytone2841632012-01-26 02:56:24 +00001063 for key, vvv in packet_total_times.items():
1064 # print ' key = (%s) "%s"' % (type(key), key)
1065 # print 'value = (%s) %s' % (type(vvv), vvv)
1066 # if type(vvv) == 'float':
1067 total_packet_time += vvv
Jim Inghamd95752f2012-03-01 18:57:51 +00001068 for key, vvv in packet_count.items():
1069 total_packet_count += vvv
1070
1071 print '#---------------------------------------------------'
Greg Claytone2841632012-01-26 02:56:24 +00001072 print '# Packet timing summary:'
Greg Clayton25f82aa2015-05-22 23:00:59 +00001073 print '# Totals: time = %6f, count = %6d' % (total_packet_time, total_packet_count)
Jim Inghamd95752f2012-03-01 18:57:51 +00001074 print '#---------------------------------------------------'
1075 print '# Packet Time (sec) Percent Count '
1076 print '#------------------------- ---------- ------- ------'
1077 if options and options.sort_count:
1078 res = sorted(packet_count, key=packet_count.__getitem__, reverse=True)
1079 else:
1080 res = sorted(packet_total_times, key=packet_total_times.__getitem__, reverse=True)
1081
Greg Claytone2841632012-01-26 02:56:24 +00001082 if last_time > 0.0:
1083 for item in res:
1084 packet_total_time = packet_total_times[item]
1085 packet_percent = (packet_total_time / total_packet_time)*100.0
1086 if packet_percent >= 10.0:
Jim Inghamd95752f2012-03-01 18:57:51 +00001087 print " %24s %.6f %.2f%% %6d" % (item, packet_total_time, packet_percent, packet_count[item])
Greg Claytone2841632012-01-26 02:56:24 +00001088 else:
Jim Inghamd95752f2012-03-01 18:57:51 +00001089 print " %24s %.6f %.2f%% %6d" % (item, packet_total_time, packet_percent, packet_count[item])
Greg Claytone2841632012-01-26 02:56:24 +00001090
1091
1092
1093if __name__ == '__main__':
Greg Clayton8ebb9a82012-06-01 20:23:54 +00001094 usage = "usage: gdbremote [options]"
1095 description='''The command disassembles a GDB remote packet log.'''
1096 parser = optparse.OptionParser(description=description, prog='gdbremote',usage=usage)
1097 parser.add_option('-v', '--verbose', action='store_true', dest='verbose', help='display verbose debug info', default=False)
1098 parser.add_option('-q', '--quiet', action='store_true', dest='quiet', help='display verbose debug info', default=False)
1099 parser.add_option('-C', '--color', action='store_true', dest='color', help='add terminal colors', default=False)
1100 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 +00001101 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 +00001102 try:
1103 (options, args) = parser.parse_args(sys.argv[1:])
1104 except:
1105 print 'error: argument error'
1106 sys.exit(1)
1107
Greg Claytonf51a23f2012-06-04 23:22:17 +00001108 options.colors = TerminalColors(options.color)
1109 options.symbolicator = None
1110 if options.crashlog:
1111 import lldb
1112 lldb.debugger = lldb.SBDebugger.Create()
1113 import lldb.macosx.crashlog
1114 options.symbolicator = lldb.macosx.crashlog.CrashLog(options.crashlog)
1115 print '%s' % (options.symbolicator)
Greg Clayton8ebb9a82012-06-01 20:23:54 +00001116
Greg Claytone2841632012-01-26 02:56:24 +00001117 # This script is being run from the command line, create a debugger in case we are
1118 # going to use any debugger functions in our function.
Greg Claytonb2273bd2015-07-17 00:19:31 +00001119 if len(args):
1120 for file in args:
1121 print '#----------------------------------------------------------------------'
1122 print "# GDB remote log file: '%s'" % file
1123 print '#----------------------------------------------------------------------'
1124 parse_gdb_log_file (file, options)
1125 if options.symbolicator:
1126 print '%s' % (options.symbolicator)
1127 else:
1128 parse_gdb_log(sys.stdin, options)
Greg Claytonf51a23f2012-06-04 23:22:17 +00001129
Greg Claytone2841632012-01-26 02:56:24 +00001130else:
1131 import lldb
1132 if lldb.debugger:
1133 # This initializer is being run from LLDB in the embedded command interpreter
1134 # Add any commands contained in this module to LLDB
1135 lldb.debugger.HandleCommand('command script add -f gdbremote.start_gdb_log start_gdb_log')
1136 lldb.debugger.HandleCommand('command script add -f gdbremote.stop_gdb_log stop_gdb_log')
1137 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'