Linux_Kernel_map4vehicle/srcxray.py

204 lines
5.4 KiB
Python
Raw Normal View History

2018-07-19 02:46:21 +08:00
#!/usr/bin/python3
#
2018-07-19 04:48:22 +08:00
# srcxray - source code X-ray
2018-07-19 02:46:21 +08:00
#
# Analyzes interconnections between functions and structures in source code.
#
# Uses cscope and git grep --show-function to
# reveal references between identifiers.
#
# 2018 Constantine Shulyupin, const@MakeLinux.com
#
2018-07-19 12:52:33 +08:00
import inspect
import random
import os
import sys
import collections
import subprocess
import re
2018-07-19 02:46:21 +08:00
2018-07-19 12:52:33 +08:00
black_list = ['aligned', '__attribute__', 'unlikely', 'typeof', 'u32',
'PVOP_CALLEE0', 'PVOP_VCALLEE0', 'PVOP_VCALLEE1', 'trace_hardirqs_off']
2018-07-19 02:46:21 +08:00
level_limit = 7
limit = 10000
n = 0
2018-07-19 04:48:22 +08:00
2018-07-19 02:46:21 +08:00
def print_limited(a):
print(a)
global n
2018-07-19 04:48:22 +08:00
n += 1
2018-07-19 02:46:21 +08:00
if n > limit:
print('Reached limit')
sys.exit(1)
2018-07-19 04:48:22 +08:00
2018-07-19 02:46:21 +08:00
def log(*args, **kwargs):
2018-07-19 12:52:33 +08:00
print(inspect.stack()[1][3],
str(*args).rstrip(), file=sys.stderr, **kwargs)
2018-07-19 02:46:21 +08:00
pass
2018-07-19 12:52:33 +08:00
2018-07-19 02:46:21 +08:00
def popen(p):
2018-07-19 13:29:29 +08:00
return subprocess.Popen(p, shell=True, stdout=subprocess.PIPE,
encoding="utf-8").stdout
2018-07-19 02:46:21 +08:00
2018-07-19 12:52:33 +08:00
2018-07-19 02:46:21 +08:00
def extract_referer(line):
line = re.sub(r'__ro_after_init', '', line)
line = re.sub(r'FNAME\((\w+)\)', r'\1', line)
line = re.sub(r'.*TRACE_EVENT.*', '', line)
m = re.match(r'^[^\s]+=[^,]*\(\*(\b\w+)\)\s*[\(\[=][^;]*$', line)
if not m:
m = re.match(r'^[^\s]+=[^,]*(\b\w+)\s*[\(\[=][^;]*$', line)
if m:
return m.group(1)
2018-07-19 12:52:33 +08:00
2018-07-19 02:46:21 +08:00
def extract_referer_test():
for a in {
"fs=good2()",
2018-07-19 13:29:29 +08:00
"f=static int fastop(struct x86_emulate_ctxt *ctxt, "
+ "void (*fop)(struct fastop *))",
2018-07-19 02:46:21 +08:00
"f=int good(a, bad (*func)(arg))",
"f=EXPORT_SYMBOL_GPL(bad);",
"f=bad (*good)()",
"f=int FNAME(good)(a)",
"f=TRACE_EVENT(a)",
2018-07-19 04:48:22 +08:00
"f: a=in bad()"}:
2018-07-19 02:46:21 +08:00
print(a, '->', extract_referer(a))
2018-07-19 12:52:33 +08:00
2018-07-19 02:46:21 +08:00
def func_referers_git_grep(name):
res = []
r = None
2018-07-19 13:29:29 +08:00
for line in popen(r'git grep --no-index --word-regexp --show-function '
r'"^\s.*\b%s"' % (name)):
# Filter out names in comment afer function,
# when comment start from ' *'
2018-07-19 02:46:21 +08:00
# To see the problem try "git grep -p and"
if re.match(r'.*: \* ', line):
r = None
2018-07-19 13:29:29 +08:00
if r and r != name and r not in black_list:
2018-07-19 02:46:21 +08:00
res.append(r)
r = None
r = extract_referer(line)
return res
2018-07-19 12:52:33 +08:00
2018-07-19 02:46:21 +08:00
cscope_warned = False
2018-07-19 12:52:33 +08:00
2018-07-19 02:46:21 +08:00
def func_referers_cscope(name):
global cscope_warned
if not os.path.isfile('cscope.out'):
if not cscope_warned:
print("Recommended: cscope -bkR", file=sys.stderr)
cscope_warned = True
return []
2018-07-19 12:52:33 +08:00
res = [l.split()[1] for l in popen(r'cscope -d -L3 "%s"' %
2018-07-19 13:29:29 +08:00
(name)) if l not in black_list]
2018-07-19 02:46:21 +08:00
if not res:
res = func_referers_git_grep(name)
return res
2018-07-19 12:52:33 +08:00
2018-07-19 02:46:21 +08:00
def func_referers_all(name):
return set(func_referers_git_grep(name) + func_referers_cscope(name))
2018-07-19 12:52:33 +08:00
def referers_tree(name, referer=None, printed=None, level=0):
2018-07-19 02:46:21 +08:00
if not referer:
if os.path.isfile('cscope.out'):
referer = func_referers_cscope
else:
2018-07-19 12:52:33 +08:00
print("Using git grep only, recommended to run: cscope -bkR",
file=sys.stderr)
2018-07-19 02:46:21 +08:00
referer = func_referers_git_grep
if isinstance(referer, str):
referer = eval(referer)
2018-07-19 12:52:33 +08:00
if not printed:
printed = set()
2018-07-19 02:46:21 +08:00
if name in printed:
print_limited(level*'\t' + name + ' ^')
return
else:
print_limited(level*'\t' + name)
printed.add(name)
if level > level_limit - 2:
print_limited((level + 1)*'\t' + '...')
return ''
listed = set()
for a in referer(name):
if a in listed:
continue
referers_tree(a, referer, printed, level + 1)
listed.add(a)
return ''
2018-07-19 12:52:33 +08:00
def call_tree(node, printed=None, level=0):
2018-07-19 02:46:21 +08:00
if not os.path.isfile('cscope.out'):
2018-07-19 12:52:33 +08:00
print("Please run: cscope -bkR", file=sys.stderr)
return False
2018-07-19 13:29:29 +08:00
if printed is None:
2018-07-19 12:52:33 +08:00
printed = set()
2018-07-19 02:46:21 +08:00
if node in printed:
2018-07-19 12:52:33 +08:00
limit = - 1
2018-07-19 04:48:22 +08:00
print_limited(level*'\t' + node + ' ^')
2018-07-19 02:46:21 +08:00
return
else:
print_limited(level*'\t' + node)
printed.add(node)
2018-07-19 04:48:22 +08:00
if level > level_limit - 2:
2018-07-19 02:46:21 +08:00
print_limited((level + 1)*'\t' + '...')
return ''
local_printed = set()
2018-07-19 12:52:33 +08:00
for line in popen('cscope -d -L2 "%s"' % (node)):
2018-07-19 13:29:29 +08:00
a = line.split()[1]
if a in local_printed or a in black_list:
2018-07-19 12:52:33 +08:00
continue
2018-07-19 13:29:29 +08:00
local_printed.add(a)
2018-07-19 02:46:21 +08:00
try:
2018-07-19 12:52:33 +08:00
call_tree(line.split()[1], printed, level + 1)
2018-07-19 13:29:29 +08:00
except Exception:
2018-07-19 02:46:21 +08:00
pass
return ''
2018-07-19 12:52:33 +08:00
2018-07-19 02:46:21 +08:00
me = os.path.basename(sys.argv[0])
2018-07-19 12:52:33 +08:00
2018-07-19 02:46:21 +08:00
def usage():
print(me, "referers_tree", "<identifier>")
print(me, "call_tree", "<identifier>")
print("Try this:")
print("cd linux/init")
print(me, "referers_tree nfs_root_data")
print(me, "call_tree start_kernel")
print(me, "Emergency termination: ^Z, kill %1")
2018-07-19 12:52:33 +08:00
2018-07-19 02:46:21 +08:00
def main():
try:
ret = False
if len(sys.argv) == 1:
print('Run', me, 'usage')
else:
2018-07-19 04:48:22 +08:00
if '(' in sys.argv[1]:
2018-07-19 02:46:21 +08:00
ret = eval(sys.argv[1])
else:
2018-07-19 12:52:33 +08:00
ret = eval(sys.argv[1] + '(' + ', '.join("'%s'" % (a)
2018-07-19 13:29:29 +08:00
for a in sys.argv[2:]) + ')')
if isinstance(ret, bool) and ret is False:
2018-07-19 02:46:21 +08:00
sys.exit(os.EX_CONFIG)
print(ret)
except KeyboardInterrupt:
warning("\nInterrupted")
2018-07-19 12:52:33 +08:00
2018-07-19 02:46:21 +08:00
if __name__ == "__main__":
main()