mirror of
https://git.rtems.org/rtems-tools/
synced 2025-05-13 08:09:16 +08:00

- Fix mi_parser on Python3. Python3 does not support the __cmp__ operator and rich comparision operators are required, See PEP 207. - Remove the global variables and make a class containing them. Update the gdb class to use the mi_parser session class. Removing the globals means the global lock in the gdb module can be removed.
455 lines
14 KiB
Python
Executable File
455 lines
14 KiB
Python
Executable File
#!/usr/bin/python
|
|
|
|
#
|
|
# Copyright (c) 2008 Michael Eddington
|
|
#
|
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
# of this software and associated documentation files (the "Software"), to deal
|
|
# in the Software without restriction, including without limitation the rights
|
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
# copies of the Software, and to permit persons to whom the Software is
|
|
# furnished to do so, subject to the following conditions:
|
|
#
|
|
# The above copyright notice and this permission notice shall be included in
|
|
# all copies or substantial portions of the Software.
|
|
#
|
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
# SOFTWARE.
|
|
#
|
|
|
|
# Authors:
|
|
# Frank Laub (frank.laub@gmail.com)
|
|
# Michael Eddington (mike@phed.org)
|
|
|
|
# $Id$
|
|
|
|
from __future__ import print_function
|
|
|
|
import re
|
|
import pprint
|
|
|
|
from . import spark
|
|
|
|
def _private():
|
|
class Token(object):
|
|
def __init__(self, type, value=None):
|
|
self.type = type
|
|
self.value = value
|
|
def __lt__(self, o):
|
|
return self.type < o
|
|
def __gt__(self, o):
|
|
return self.type > o
|
|
def __le__(self, o):
|
|
return self.type <= o
|
|
def __ge__(self, o):
|
|
return self.type >= o
|
|
def __eq__(self, o):
|
|
return self.type == o
|
|
def __ne__(self, o):
|
|
return self.type != o
|
|
def __repr__(self):
|
|
return self.value or self.type
|
|
|
|
class AST(object):
|
|
def __init__(self, type):
|
|
self.type = type
|
|
self._kids = []
|
|
def __getitem__(self, i):
|
|
return self._kids[i]
|
|
def __setitem__(self, i, k):
|
|
self._kids[i] = k
|
|
def __len__(self):
|
|
return len(self._kids)
|
|
def __lt__(self, o):
|
|
return self.type < o
|
|
def __gt__(self, o):
|
|
return self.type > o
|
|
def __le__(self, o):
|
|
return self.type <= o
|
|
def __ge__(self, o):
|
|
return self.type >= o
|
|
def __eq__(self, o):
|
|
return self.type == o
|
|
def __ne__(self, o):
|
|
return self.type != o
|
|
|
|
class GdbMiScannerBase(spark.GenericScanner):
|
|
def tokenize(self, input):
|
|
self.rv = []
|
|
spark.GenericScanner.tokenize(self, input)
|
|
return self.rv
|
|
|
|
def t_nl(self, s):
|
|
r'\n|\r\n'
|
|
self.rv.append(Token('nl'))
|
|
|
|
def t_whitespace(self, s):
|
|
r'[ \t\f\v]+'
|
|
pass
|
|
|
|
def t_symbol(self, s):
|
|
r',|\{|\}|\[|\]|\='
|
|
self.rv.append(Token(s, s))
|
|
|
|
def t_result_type(self, s):
|
|
r'\*|\+|\^'
|
|
self.rv.append(Token('result_type', s))
|
|
|
|
def t_stream_type(self, s):
|
|
r'\@|\&|\~'
|
|
self.rv.append(Token('stream_type', s))
|
|
|
|
def t_string(self, s):
|
|
r'[\w-]+'
|
|
self.rv.append(Token('string', s))
|
|
|
|
def t_c_string(self, s):
|
|
r'\".*?(?<![\\\\])\"'
|
|
inner = self.__unescape(s[1:len(s)-1])
|
|
self.rv.append(Token('c_string', inner))
|
|
|
|
def t_default(self, s):
|
|
r'( . | \n )+'
|
|
raise Exception("Specification error: unmatched input for '%s'" % s)
|
|
|
|
def __unescape(self, s):
|
|
s = re.sub(r'\\r', r'\r', s)
|
|
s = re.sub(r'\\n', r'\n', s)
|
|
s = re.sub(r'\\t', r'\t', s)
|
|
return re.sub(r'\\(.)', r'\1', s)
|
|
|
|
|
|
class GdbMiScanner(GdbMiScannerBase):
|
|
def t_token(self, s):
|
|
r'\d+'
|
|
self.rv.append(Token('token', s))
|
|
|
|
class GdbMiParser(spark.GenericASTBuilder):
|
|
def __init__(self):
|
|
spark.GenericASTBuilder.__init__(self, AST, 'output')
|
|
|
|
def p_output(self, args):
|
|
'''
|
|
output ::= record_list
|
|
record_list ::= generic_record
|
|
record_list ::= generic_record record_list
|
|
generic_record ::= result_record
|
|
generic_record ::= stream_record
|
|
result_record ::= result_header result_list nl
|
|
result_record ::= result_header nl
|
|
result_header ::= token result_type class
|
|
result_header ::= result_type class
|
|
result_header ::= token = class
|
|
result_header ::= = class
|
|
stream_record ::= stream_type c_string nl
|
|
result_list ::= , result result_list
|
|
result_list ::= , result
|
|
result_list ::= , tuple
|
|
result ::= variable = value
|
|
class ::= string
|
|
variable ::= string
|
|
value ::= const
|
|
value ::= tuple
|
|
value ::= list
|
|
value_list ::= , value
|
|
value_list ::= , value value_list
|
|
const ::= c_string
|
|
tuple ::= { }
|
|
tuple ::= { result }
|
|
tuple ::= { result result_list }
|
|
list ::= [ ]
|
|
list ::= [ value ]
|
|
list ::= [ value value_list ]
|
|
list ::= [ result ]
|
|
list ::= [ result result_list ]
|
|
list ::= { value }
|
|
list ::= { value value_list }
|
|
'''
|
|
pass
|
|
|
|
def terminal(self, token):
|
|
# Homogeneous AST.
|
|
rv = AST(token.type)
|
|
rv.value = token.value
|
|
return rv
|
|
|
|
def nonterminal(self, type, args):
|
|
# Flatten AST a bit by not making nodes if there's only one child.
|
|
exclude = [
|
|
'record_list'
|
|
]
|
|
if len(args) == 1 and type not in exclude:
|
|
return args[0]
|
|
return spark.GenericASTBuilder.nonterminal(self, type, args)
|
|
|
|
def error(self, token, i=0, tokens=None):
|
|
if i > 2:
|
|
print('%s %s %s %s' % (tokens[i-3], tokens[i-2], tokens[i-1], tokens[i]))
|
|
raise Exception("Syntax error at or near %d:'%s' token" % (i, token))
|
|
|
|
class GdbMiInterpreter(spark.GenericASTTraversal):
|
|
def __init__(self, ast):
|
|
spark.GenericASTTraversal.__init__(self, ast)
|
|
self.postorder()
|
|
|
|
def __translate_type(self, type):
|
|
table = {
|
|
'^': 'result',
|
|
'=': 'notify',
|
|
'+': 'status',
|
|
'*': 'exec',
|
|
'~': 'console',
|
|
'@': 'target',
|
|
'&': 'log'
|
|
}
|
|
return table[type]
|
|
|
|
def n_result(self, node):
|
|
# result ::= variable = value
|
|
node.value = { node[0].value: node[2].value }
|
|
#print 'result: %s' % node.value
|
|
|
|
def n_tuple(self, node):
|
|
if len(node) == 2:
|
|
# tuple ::= {}
|
|
node.value = {}
|
|
elif len(node) == 3:
|
|
# tuple ::= { result }
|
|
node.value = node[1].value
|
|
elif len(node) == 4:
|
|
# tuple ::= { result result_list }
|
|
node.value = node[1].value
|
|
for result in node[2].value:
|
|
for n, v in list(result.items()):
|
|
if n in node.value:
|
|
#print '**********list conversion: [%s] %s -> %s' % (n, node.value[n], v)
|
|
old = node.value[n]
|
|
if not isinstance(old, list):
|
|
node.value[n] = [ node.value[n] ]
|
|
node.value[n].append(v)
|
|
else:
|
|
node.value[n] = v
|
|
else:
|
|
raise Exception('Invalid tuple')
|
|
#print 'tuple: %s' % node.value
|
|
|
|
def n_list(self, node):
|
|
if len(node) == 2:
|
|
# list ::= []
|
|
node.value = []
|
|
elif len(node) == 3:
|
|
# list ::= [ value ]
|
|
node.value = [ node[1].value ]
|
|
elif len(node) == 4:
|
|
# list ::= [ value value_list ]
|
|
node.value = [ node[1].value ] + node[2].value
|
|
#list ::= [ result ]
|
|
#list ::= [ result result_list ]
|
|
#list ::= { value }
|
|
#list ::= { value value_list }
|
|
#print 'list %s' % node.value
|
|
|
|
def n_value_list(self, node):
|
|
if len(node) == 2:
|
|
#value_list ::= , value
|
|
node.value = [ node[1].value ]
|
|
elif len(node) == 3:
|
|
#value_list ::= , value value_list
|
|
node.value = [ node[1].value ] + node[2].value
|
|
|
|
def n_result_list(self, node):
|
|
if len(node) == 2:
|
|
# result_list ::= , result
|
|
node.value = [ node[1].value ]
|
|
else:
|
|
# result_list ::= , result result_list
|
|
node.value = [ node[1].value ] + node[2].value
|
|
#print 'result_list: %s' % node.value
|
|
|
|
def n_result_record(self, node):
|
|
node.value = node[0].value
|
|
if len(node) == 3:
|
|
# result_record ::= result_header result_list nl
|
|
node.value['results'] = node[1].value
|
|
elif len(node) == 2:
|
|
# result_record ::= result_header nl
|
|
pass
|
|
#print 'result_record: %s' % (node.value)
|
|
|
|
def n_result_header(self, node):
|
|
if len(node) == 3:
|
|
# result_header ::= token result_type class
|
|
node.value = {
|
|
'token': node[0].value,
|
|
'type': self.__translate_type(node[1].value),
|
|
'class_': node[2].value,
|
|
'record_type': 'result'
|
|
}
|
|
elif len(node) == 2:
|
|
# result_header ::= result_type class
|
|
node.value = {
|
|
'token': None,
|
|
'type': self.__translate_type(node[0].value),
|
|
'class_': node[1].value,
|
|
'record_type': 'result'
|
|
}
|
|
|
|
def n_stream_record(self, node):
|
|
# stream_record ::= stream_type c_string nl
|
|
node.value = {
|
|
'type': self.__translate_type(node[0].value),
|
|
'value': node[1].value,
|
|
'record_type': 'stream'
|
|
}
|
|
#print 'stream_record: %s' % node.value
|
|
|
|
def n_record_list(self, node):
|
|
if len(node) == 1:
|
|
# record_list ::= generic_record
|
|
node.value = [ node[0].value ]
|
|
elif len(node) == 2:
|
|
# record_list ::= generic_record record_list
|
|
node.value = [ node[0].value ] + node[1].value
|
|
#print 'record_list: %s' % node.value
|
|
|
|
#def default(self, node):
|
|
#print 'default: ' + node.type
|
|
|
|
class GdbDynamicObject(object):
|
|
def __init__(self, dict_):
|
|
self.graft(dict_)
|
|
|
|
def __repr__(self):
|
|
return pprint.pformat(self.__dict__)
|
|
|
|
def __bool__(self):
|
|
return len(self.__dict__) > 0
|
|
|
|
def __getitem__(self, i):
|
|
if i == 0 and len(self.__dict__) > 0:
|
|
return self
|
|
else:
|
|
raise IndexError
|
|
|
|
def __getattr__(self, name):
|
|
if name.startswith('__'):
|
|
raise AttributeError
|
|
return None
|
|
|
|
def graft(self, dict_):
|
|
for name, value in list(dict_.items()):
|
|
name = name.replace('-', '_')
|
|
if isinstance(value, dict):
|
|
value = GdbDynamicObject(value)
|
|
elif isinstance(value, list):
|
|
x = value
|
|
value = []
|
|
for item in x:
|
|
if isinstance(item, dict):
|
|
item = GdbDynamicObject(item)
|
|
value.append(item)
|
|
setattr(self, name, value)
|
|
|
|
class GdbMiRecord:
|
|
def __init__(self, record):
|
|
self.result = None
|
|
for name, value in list(record[0].items()):
|
|
name = name.replace('-', '_')
|
|
if name == 'results':
|
|
for result in value:
|
|
if not self.result:
|
|
self.result = GdbDynamicObject(result)
|
|
else:
|
|
# graft this result to self.results
|
|
self.result.graft(result)
|
|
else:
|
|
setattr(self, name, value)
|
|
|
|
def __repr__(self):
|
|
return pprint.pformat(self.__dict__)
|
|
|
|
return (GdbMiScanner(), GdbMiParser(), GdbMiInterpreter, GdbMiRecord)
|
|
|
|
|
|
class session(object):
|
|
def __init__(self):
|
|
(self.the_scanner,
|
|
self.the_parser,
|
|
self.the_interpreter,
|
|
self.the_output) = _private()
|
|
|
|
def scan(self, input):
|
|
return self.the_scanner.tokenize(input)
|
|
|
|
def parse(self, tokens):
|
|
return self.the_parser.parse(tokens)
|
|
|
|
def process(self, input):
|
|
tokens = self.scan(input)
|
|
ast = self.parse(tokens)
|
|
self.the_interpreter(ast)
|
|
return self.the_output(ast.value)
|
|
|
|
#
|
|
# Not updated with the session class
|
|
#
|
|
if __name__ == '__main__':
|
|
def main():
|
|
def print_tokens(tokens):
|
|
print()
|
|
for token in tokens:
|
|
if token.value:
|
|
print(token.type + ': ' + token.value)
|
|
else:
|
|
print(token.type)
|
|
|
|
def run_test(test):
|
|
lines = test.splitlines()
|
|
for line in lines:
|
|
tokens = scan(line + '\n')
|
|
#print_tokens(tokens)
|
|
|
|
ast = parse(tokens)
|
|
__the_interpreter(ast)
|
|
output = __the_output(ast.value)
|
|
print(output)
|
|
|
|
x = '"No symbol table is loaded. Use the \\"file\\" command."'
|
|
m = re.match('\".*?(?<![\\\\])\"', x)
|
|
z = x[m.start():m.end()]
|
|
|
|
test1 = '22^done,time={wallclock="0.05395",user="0.02996",system="0.02222",start="1210321030.972724",end="1210321031.026675"}\n'
|
|
test2 = '''~"[Switching to process 3832 local thread 0x3607]\\n"
|
|
=shlibs-updated
|
|
^running
|
|
'''
|
|
|
|
test3 = '''=shlibs-added,shlib-info={num="2",name="qi",kind="-",dyld-addr="0x1000",reason="exec",requested-state="Y",state="Y",path="/Users/franklaub/bin/qi",description="/Users/franklaub/bin/qi",loaded_addr="",slide="0x0",prefix="",dsym-objpath="/Users/franklaub/bin/qi.dSYM/Contents/Resources/DWARF/qi"},time={now="1210290757.432413"}
|
|
=shlibs-added,shlib-info={num="3",name="libgcc_s.1.dylib",kind="-",dyld-addr="0x9230a000",reason="dyld",requested-state="Y",state="Y",path="/usr/lib/libgcc_s.1.dylib",description="/usr/lib/libgcc_s.1.dylib",loaded_addr="0x9230a000",slide="-0x6dcf6000",prefix=""},time={now="1210290757.432771"}
|
|
=shlibs-added,shlib-info={num="4",name="libSystem.B.dylib",kind="-",dyld-addr="0x950aa000",reason="dyld",requested-state="Y",state="Y",path="/usr/lib/libSystem.B.dylib",description="/usr/lib/libSystem.B.dylib",loaded_addr="0x950aa000",slide="-0x6af56000",prefix="",commpage-objpath="/usr/lib/libSystem.B.dylib[LC_SEGMENT.__DATA.__commpage]"},time={now="1210290757.433091"}
|
|
=shlibs-added,shlib-info={num="5",name="libmathCommon.A.dylib",kind="-",dyld-addr="0x95018000",reason="dyld",requested-state="Y",state="Y",path="/usr/lib/system/libmathCommon.A.dylib",description="/usr/lib/system/libmathCommon.A.dylib",loaded_addr="0x95018000",slide="-0x6afe8000",prefix=""},time={now="1210290757.433390"}
|
|
*stopped,time={wallclock="1.02740",user="0.00379",system="0.00791",start="1210290756.408774",end="1210290757.436179"},reason="breakpoint-hit",commands="no",times="1",bkptno="1",thread-id="1"
|
|
'''
|
|
|
|
test4 = '''=shlibs-added,shlib-info={num="2",name="qi",kind="-",dyld-addr="0x1000",reason="exec",requested-state="Y",state="Y",path="/Users/franklaub/bin/qi",description="/Users/franklaub/bin/qi",loaded_addr="",slide="0x0",prefix="",dsym-objpath="/Users/franklaub/bin/qi.dSYM/Contents/Resources/DWARF/qi"},time={now="1210290757.432413"}
|
|
^running
|
|
'''
|
|
test5 = '''=class,variable={frame={x="2"},frame={x="2"}, regs={"1","2","3"}}
|
|
^running
|
|
'''
|
|
test6 = '10^done,stack-args={frame={level="0",args={}}},time={wallclock="0.00006",user="0.00004",system="0.00002",start="1210530442.460765",end="1210530442.460825"}\n'
|
|
|
|
run_test(test1)
|
|
run_test(test2)
|
|
run_test(test3)
|
|
run_test(test4)
|
|
run_test(test5)
|
|
run_test(test6)
|
|
|
|
main()
|