286 lines
9.7 KiB
Python
Executable File
286 lines
9.7 KiB
Python
Executable File
#!/usr/bin/env python
|
|
#
|
|
# Dan Aloni (c), 2003
|
|
#
|
|
# I use this script in order to automatically add trace macros
|
|
# to C functions inside coLinux so I'd be able to debug it better.
|
|
#
|
|
# It is not active by default, since it slows down the compilation by
|
|
# a factor of 4.
|
|
#
|
|
# Optionally, we could improve this to be able to output a complete
|
|
# trace of the kernel (not including inline functions).
|
|
#
|
|
|
|
import re, os, sys
|
|
|
|
class Error(Exception): pass
|
|
|
|
# Reduced tokenizing regular expression
|
|
|
|
c_identifier = r'(?P<identifier>[a-zA-Z_][a-zA-Z_0-9]*)'
|
|
c_start_comment = r'(?P<start_comment>\/\*)'
|
|
c_preprocessor = r'(?P<preprocessor>#)'
|
|
c_space = r'(?P<space>[ \t\n])'
|
|
c_string = r'(?P<string>")'
|
|
c_character = r'(?P<character>(\'\\[0-9]+\')|\'\\\'\'|\'.\'|\'\'\'\'|\'\\.\')'
|
|
c_number = r'(?P<number>(0x)?[0-9]+)'
|
|
c_open_bracet = r'(?P<open_bracet>[({\[])'
|
|
c_close_bracet = r'(?P<close_bracet>[)}\]])'
|
|
c_operators = r'(?P<operators>\>=|\<\<|\>\>|\|=|--|\+\+|-=|!=|->|' + \
|
|
r'[+]=|[-?^|.%:/&*,=;+<~!>])'
|
|
|
|
c_token = re.compile(
|
|
'(' + '|'.join(
|
|
[c_identifier,
|
|
c_start_comment,
|
|
c_preprocessor,
|
|
c_space,
|
|
c_string,
|
|
c_character,
|
|
c_number,
|
|
c_open_bracet,
|
|
c_close_bracet,
|
|
c_operators,
|
|
]) + ')'
|
|
)
|
|
|
|
class CParser(object):
|
|
def __init__(self, data):
|
|
self.data = data
|
|
self.pos = 0
|
|
|
|
def run(self):
|
|
self.parse_c()
|
|
|
|
def token(self, token, type=None):
|
|
print [token, type]
|
|
|
|
def parse_c_comment(self):
|
|
pos = self.data.find('*/', self.pos)
|
|
if pos == -1:
|
|
raise Error('Unterminated comment')
|
|
|
|
self.token(self.data[self.pos-2:pos+2], type='comment')
|
|
self.pos = pos + 2
|
|
|
|
def parse_c_string(self):
|
|
pos = self.pos
|
|
while 1:
|
|
if self.data[pos] == '\\':
|
|
pos += 2
|
|
continue
|
|
|
|
if self.data[pos] != '"':
|
|
pos += 1
|
|
continue
|
|
|
|
if pos >= len(self.data):
|
|
raise Error('Unterminated string')
|
|
|
|
break
|
|
|
|
self.token(self.data[self.pos-1:pos+1], type='string')
|
|
self.pos = pos + 1
|
|
|
|
def parse_c_preprocessor(self):
|
|
pos = self.pos
|
|
while 1:
|
|
pos = self.data.find('\n', pos)
|
|
if pos == -1:
|
|
raise Error('Unterminated macro')
|
|
if self.data[pos-1] == '\\':
|
|
pos = pos+1
|
|
else:
|
|
break
|
|
self.token(self.data[self.pos-1:pos+1], type='preprocessor')
|
|
self.pos = pos + 1
|
|
|
|
def error(self):
|
|
pass
|
|
|
|
def parse_c(self):
|
|
while self.pos < len(self.data):
|
|
m = c_token.match(self.data, self.pos)
|
|
if not m:
|
|
self.error()
|
|
raise Error("Parsing at %r" % (self.data[self.pos:self.pos+50], ))
|
|
self.pos = m.end()
|
|
raw = m.groups(0)[0]
|
|
dict = m.groupdict()
|
|
if dict['start_comment']:
|
|
self.parse_c_comment()
|
|
elif dict['string']:
|
|
self.parse_c_string()
|
|
elif dict['preprocessor']:
|
|
self.parse_c_preprocessor()
|
|
elif dict['identifier']:
|
|
self.token(raw, 'identifier')
|
|
elif dict['space']:
|
|
self.token(raw, 'space')
|
|
elif dict['open_bracet']:
|
|
self.token(raw, 'open_bracet')
|
|
elif dict['close_bracet']:
|
|
self.token(raw, 'close_bracet')
|
|
else:
|
|
self.token(raw)
|
|
|
|
class CTracer(CParser):
|
|
def __init__(self, data, outfile):
|
|
super(CTracer, self).__init__(data)
|
|
self.bracet_level = 0
|
|
self.last_tokens = []
|
|
self.last_tokens_types = []
|
|
self.last_level1_token = None
|
|
self.bracet = []
|
|
self.sub_tokens = []
|
|
self.sub_tokens_with_return_trace = []
|
|
self.in_return = False
|
|
self.in_return_skip_space = False
|
|
self.return_tokens = []
|
|
self.params_list = []
|
|
self.outfile = outfile
|
|
self.func_name = None
|
|
self.activated = True
|
|
self.stop_count = 0
|
|
self.debug_tokens = []
|
|
|
|
self.outfile.write('extern void co_trace_ent(void *);\n');
|
|
self.outfile.write('extern void co_trace_ent_name(void *, const char *);\n');
|
|
self.outfile.write('extern void co_trace_ret(void *);\n');
|
|
self.outfile.write(
|
|
"""
|
|
#define CO_TRACE_RET_VALUE(_value_) ({ \
|
|
typeof(_value_) __ret_value__; \
|
|
co_trace_ret((void *)&TRACE_FUNCTION_NAME); \
|
|
__ret_value__ = _value_; \
|
|
})
|
|
|
|
#define CO_TRACE_RET { \
|
|
co_trace_ret((void *)&TRACE_FUNCTION_NAME); \
|
|
}
|
|
|
|
""")
|
|
|
|
|
|
def error(self):
|
|
for debug in self.debug_tokens:
|
|
print debug
|
|
|
|
def token(self, token, type=None):
|
|
self.debug_tokens.append((token, type))
|
|
if len(self.debug_tokens) > 40:
|
|
del self.debug_tokens[0]
|
|
|
|
if type == 'close_bracet':
|
|
self.bracet_level -= 1
|
|
del self.bracet[0]
|
|
|
|
if self.bracet_level == 0:
|
|
if type != 'space':
|
|
self.last_tokens.append(token)
|
|
self.last_tokens_types.append(type)
|
|
if len(self.last_tokens) > 40:
|
|
del self.last_tokens[0]
|
|
if len(self.last_tokens_types) > 40:
|
|
del self.last_tokens_types[0]
|
|
if self.last_tokens[-4:] == ['(', ')', '{', '}']:
|
|
if self.last_tokens_types[-5] == 'identifier':
|
|
pos = 6
|
|
self.func_name = self.last_tokens[-5]
|
|
while pos <= len(self.last_tokens):
|
|
if self.last_tokens_types[-pos] == 'close_bracet':
|
|
break
|
|
if self.last_tokens[-pos] in ['inline', '__inline__']:
|
|
self.func_name = None
|
|
break
|
|
pos += 1
|
|
|
|
elif self.bracet_level >= 1:
|
|
if self.bracet_level == 1:
|
|
if self.bracet[0] == '(':
|
|
if token == ',':
|
|
if self.last_level1_token:
|
|
self.params_list.append(self.last_level1_token)
|
|
if type == 'identifier':
|
|
self.last_level1_token = token
|
|
else:
|
|
self.last_level1_token = None
|
|
|
|
if self.in_return:
|
|
no_sub = False
|
|
if self.in_return_skip_space:
|
|
if type == 'space':
|
|
self.sub_tokens_with_return_trace.append(token)
|
|
self.sub_tokens.append(token)
|
|
no_sub = True
|
|
else:
|
|
self.in_return_skip_space = False
|
|
|
|
if not no_sub:
|
|
if token == ';' and self.in_return_bracet_level == self.bracet_level:
|
|
self.sub_tokens_with_return_trace += ['do {CO_TRACE_RET; return '] + self.return_tokens + ['; } while(0)']
|
|
# self.sub_tokens_with_return_trace += ['return CO_TRACE_RET_VALUE('] + self.return_tokens + [')']
|
|
self.sub_tokens += self.return_tokens
|
|
self.return_tokens = []
|
|
self.in_return = False
|
|
self.sub_tokens_with_return_trace.append(token)
|
|
self.sub_tokens.append(token)
|
|
else:
|
|
self.return_tokens.append(token)
|
|
else:
|
|
if not token == 'return':
|
|
self.sub_tokens_with_return_trace.append(token)
|
|
self.sub_tokens.append(token)
|
|
|
|
if token == 'return':
|
|
self.in_return = True
|
|
self.in_return_skip_space = True
|
|
self.in_return_bracet_level = self.bracet_level;
|
|
|
|
if type == 'close_bracet':
|
|
if self.bracet_level == 0 :
|
|
if token == '}' and self.activated and self.func_name != None:
|
|
params_str = ''
|
|
#params_str = ' '.join(['TRACE_X(%s)' % (x, ) for x in self.params_list])
|
|
self.outfile.write('\n#define TRACE_FUNCTION_NAME %s\n' % (self.func_name, ))
|
|
self.outfile.write(' co_trace_ent((void *)&%s); {' % (self.func_name, ))
|
|
self.outfile.write(''.join(self.sub_tokens_with_return_trace))
|
|
self.outfile.write('}; CO_TRACE_RET; ')
|
|
self.outfile.write('\n#undef TRACE_FUNCTION_NAME\n')
|
|
else:
|
|
self.outfile.write(''.join(self.sub_tokens))
|
|
self.func_name = None
|
|
|
|
if token == ')':
|
|
if self.last_level1_token:
|
|
self.params_list.append(self.last_level1_token)
|
|
|
|
if self.bracet_level == 0:
|
|
skip_token = False
|
|
if type == 'identifier':
|
|
if token == 'CO_TRACE_STOP':
|
|
skip_token = True
|
|
self.stop_count += 1;
|
|
self.activated = False
|
|
elif token == 'CO_TRACE_CONTINUE':
|
|
skip_token = True
|
|
self.stop_count -= 1;
|
|
if self.stop_count == 0:
|
|
self.activated = True
|
|
|
|
if not skip_token:
|
|
self.outfile.write(token)
|
|
|
|
if type == 'open_bracet':
|
|
self.bracet_level += 1
|
|
self.bracet.append(token)
|
|
if self.bracet_level == 1:
|
|
self.sub_tokens = []
|
|
self.sub_tokens_with_return_trace = []
|
|
if token == '(':
|
|
self.params_list = []
|
|
|
|
if __name__ == '__main__':
|
|
CTracer(open(sys.argv[1]).read(), sys.stdout).run()
|