1 #!/usr/bin/python
2
3 # Copyright (C) 2013 Oracle.
4 #
5 # Licensed under the Open Software License version 1.1
6
7 import sqlite3
8 import sys
9 import re
10
11 try:
12 con = sqlite3.connect('smatch_db.sqlite')
13 except sqlite3.Error, e:
14 print "Error %s:" % e.args[0]
15 sys.exit(1)
16
17 def usage():
18 print "%s" %(sys.argv[0])
19 print "<function> - how a function is called"
20 print "info <type> - how a function is called, filtered by type"
21 print "return_states <function> - what a function returns"
22 print "call_tree <function> - show the call tree"
23 print "where <struct_type> <member> - where a struct member is set"
24 print "type_size <struct_type> <member> - how a struct member is allocated"
25 print "data_info <struct_type> <member> - information about a given data type"
26 print "function_ptr <function> - which function pointers point to this"
27 print "trace_param <function> <param> - trace where a parameter came from"
28 print "locals <file> - print the local values in a file."
29 sys.exit(1)
30
31 function_ptrs = []
32 searched_ptrs = []
33 def get_function_pointers_helper(func):
34 cur = con.cursor()
35 cur.execute("select distinct ptr from function_ptr where function = '%s';" %(func))
36 for row in cur:
37 ptr = row[0]
38 if ptr in function_ptrs:
39 continue
40 function_ptrs.append(ptr)
41 if not ptr in searched_ptrs:
42 searched_ptrs.append(ptr)
43 get_function_pointers_helper(ptr)
44
45 def get_function_pointers(func):
46 global function_ptrs
47 global searched_ptrs
250
251 def get_next_str(txt):
252 val = ""
253 parsed = 0
254
255 if txt[0] == '(':
256 parsed += 1
257 for char in txt[1:]:
258 if char == ')':
259 break
260 parsed += 1
261 val = txt[1:parsed]
262 parsed += 1
263 elif txt[0] == 's' or txt[0] == 'u':
264 parsed += 6
265 val = txt[:parsed]
266 else:
267 if txt[0] == '-':
268 parsed += 1
269 for char in txt[parsed:]:
270 if char == '-':
271 break
272 parsed += 1
273 val = txt[:parsed]
274 return [parsed, val]
275
276 def txt_to_rl(txt):
277 if len(txt) == 0:
278 return []
279
280 ret = []
281 pairs = txt.split(",")
282 for pair in pairs:
283 cnt, min_str = get_next_str(pair)
284 if cnt == len(pair):
285 max_str = min_str
286 else:
287 cnt, max_str = get_next_str(pair[cnt + 1:])
288 min_val = txt_to_val(min_str)
289 max_val = txt_to_val(max_str)
290 ret.append([min_val, max_val])
525 return
526 printed_funcs.append(func)
527 callers = get_callers(func)
528 if len(callers) >= 20:
529 print "Over 20 callers for %s()" %(func)
530 return
531 for caller in callers:
532 call_tree_helper(caller, indent + 2)
533
534 def print_call_tree(func):
535 global printed_funcs
536 printed_funcs = []
537 call_tree_helper(func)
538
539 def function_type_value(struct_type, member):
540 cur = con.cursor()
541 cur.execute("select * from function_type_value where type like '(struct %s)->%s';" %(struct_type, member))
542 for txt in cur:
543 print "%-30s | %-30s | %s | %s" %(txt[0], txt[1], txt[2], txt[3])
544
545 def trace_callers(func, param):
546 sources = []
547 prev_type = 0
548
549 cur = con.cursor()
550 ptrs = get_function_pointers(func)
551 for ptr in ptrs:
552 cur.execute("select type, caller, value from caller_info where function = '%s' and (type = 0 or type = 1014 or type = 1028) and (parameter = -1 or parameter = %d);" %(ptr, param))
553 for row in cur:
554 data_type = int(row[0])
555 if data_type == 1014:
556 sources.append((row[1], row[2]))
557 elif data_type == 1028:
558 sources.append(("%", row[2])) # hack...
559 elif data_type == 0 and prev_type == 0:
560 sources.append((row[1], ""))
561 prev_type = data_type
562 return sources
563
564 def trace_param_helper(func, param, indent = 0):
565 global printed_funcs
566 if func in printed_funcs:
567 return
568 print "%s%s(param %d)" %(" " * indent, func, param)
569 if func == "too common":
570 return
571 if indent > 20:
572 return
573 printed_funcs.append(func)
574 sources = trace_callers(func, param)
575 for path in sources:
576
577 if len(path[1]) and path[1][0] == 'p' and path[1][1] == ' ':
578 p = int(path[1][2:])
579 trace_param_helper(path[0], p, indent + 2)
580 elif len(path[0]) and path[0][0] == '%':
581 print " %s%s" %(" " * indent, path[1])
582 else:
583 print "* %s%s %s" %(" " * (indent - 1), path[0], path[1])
584
585 def trace_param(func, param):
586 global printed_funcs
587 printed_funcs = []
588 print "tracing %s %d" %(func, param)
589 trace_param_helper(func, param)
590
591 def print_locals(filename):
592 cur = con.cursor()
593 cur.execute("select file,data,value from data_info where file = '%s' and type = 8029 and value != 0;" %(filename))
594 for txt in cur:
595 print "%s | %s | %s" %(txt[0], txt[1], txt[2])
596
597 def constraint(struct_type, member):
598 cur = con.cursor()
624 print_fn_ptrs(func)
625 elif sys.argv[1] == "return_states":
626 func = sys.argv[2]
627 print_return_states(func)
628 print "================================================"
629 print_return_implies(func)
630 elif sys.argv[1] == "return_implies":
631 func = sys.argv[2]
632 print_return_implies(func)
633 elif sys.argv[1] == "type_size" or sys.argv[1] == "buf_size":
634 struct_type = sys.argv[2]
635 member = sys.argv[3]
636 print_type_size(struct_type, member)
637 elif sys.argv[1] == "data_info":
638 struct_type = sys.argv[2]
639 member = sys.argv[3]
640 print_data_info(struct_type, member)
641 elif sys.argv[1] == "call_tree":
642 func = sys.argv[2]
643 print_call_tree(func)
644 elif sys.argv[1] == "where":
645 if len(sys.argv) == 3:
646 struct_type = "%"
647 member = sys.argv[2]
648 elif len(sys.argv) == 4:
649 struct_type = sys.argv[2]
650 member = sys.argv[3]
651 function_type_value(struct_type, member)
652 elif sys.argv[1] == "local":
653 filename = sys.argv[2]
654 variable = ""
655 if len(sys.argv) == 4:
656 variable = sys.argv[3]
657 local_values(filename, variable)
658 elif sys.argv[1] == "functions":
659 member = sys.argv[2]
660 print_functions(member)
661 elif sys.argv[1] == "trace_param":
662 if len(sys.argv) != 4:
663 usage()
664 func = sys.argv[2]
665 param = int(sys.argv[3])
666 trace_param(func, param)
667 elif sys.argv[1] == "locals":
668 if len(sys.argv) != 3:
669 usage()
670 filename = sys.argv[2]
671 print_locals(filename);
672 elif sys.argv[1] == "constraint":
673 if len(sys.argv) == 3:
674 struct_type = "%"
675 member = sys.argv[2]
676 elif len(sys.argv) == 4:
677 struct_type = sys.argv[2]
678 member = sys.argv[3]
679 constraint(struct_type, member)
680 elif sys.argv[1] == "test":
681 filename = sys.argv[2]
682 func = sys.argv[3]
683 caller_info_values(filename, func)
684 else:
685 usage()
|
1 #!/usr/bin/python
2
3 # Copyright (C) 2013 Oracle.
4 #
5 # Licensed under the Open Software License version 1.1
6
7 import sqlite3
8 import sys
9 import re
10 import subprocess
11
12 try:
13 con = sqlite3.connect('smatch_db.sqlite')
14 except sqlite3.Error, e:
15 print "Error %s:" % e.args[0]
16 sys.exit(1)
17
18 def usage():
19 print "%s" %(sys.argv[0])
20 print "<function> - how a function is called"
21 print "info <type> - how a function is called, filtered by type"
22 print "return_states <function> - what a function returns"
23 print "call_tree <function> - show the call tree"
24 print "where <struct_type> <member> - where a struct member is set"
25 print "type_size <struct_type> <member> - how a struct member is allocated"
26 print "data_info <struct_type> <member> - information about a given data type"
27 print "function_ptr <function> - which function pointers point to this"
28 print "trace_param <function> <param> - trace where a parameter came from"
29 print "find_tagged <function> <param> - find the source of a tagged value (arm64)"
30 print "parse_warns_tagged <smatch_warns.txt> - parse warns file for summary of tagged issues (arm64)"
31 print "locals <file> - print the local values in a file."
32 sys.exit(1)
33
34 function_ptrs = []
35 searched_ptrs = []
36 def get_function_pointers_helper(func):
37 cur = con.cursor()
38 cur.execute("select distinct ptr from function_ptr where function = '%s';" %(func))
39 for row in cur:
40 ptr = row[0]
41 if ptr in function_ptrs:
42 continue
43 function_ptrs.append(ptr)
44 if not ptr in searched_ptrs:
45 searched_ptrs.append(ptr)
46 get_function_pointers_helper(ptr)
47
48 def get_function_pointers(func):
49 global function_ptrs
50 global searched_ptrs
253
254 def get_next_str(txt):
255 val = ""
256 parsed = 0
257
258 if txt[0] == '(':
259 parsed += 1
260 for char in txt[1:]:
261 if char == ')':
262 break
263 parsed += 1
264 val = txt[1:parsed]
265 parsed += 1
266 elif txt[0] == 's' or txt[0] == 'u':
267 parsed += 6
268 val = txt[:parsed]
269 else:
270 if txt[0] == '-':
271 parsed += 1
272 for char in txt[parsed:]:
273 if char == '-' or char == '[':
274 break
275 parsed += 1
276 val = txt[:parsed]
277 return [parsed, val]
278
279 def txt_to_rl(txt):
280 if len(txt) == 0:
281 return []
282
283 ret = []
284 pairs = txt.split(",")
285 for pair in pairs:
286 cnt, min_str = get_next_str(pair)
287 if cnt == len(pair):
288 max_str = min_str
289 else:
290 cnt, max_str = get_next_str(pair[cnt + 1:])
291 min_val = txt_to_val(min_str)
292 max_val = txt_to_val(max_str)
293 ret.append([min_val, max_val])
528 return
529 printed_funcs.append(func)
530 callers = get_callers(func)
531 if len(callers) >= 20:
532 print "Over 20 callers for %s()" %(func)
533 return
534 for caller in callers:
535 call_tree_helper(caller, indent + 2)
536
537 def print_call_tree(func):
538 global printed_funcs
539 printed_funcs = []
540 call_tree_helper(func)
541
542 def function_type_value(struct_type, member):
543 cur = con.cursor()
544 cur.execute("select * from function_type_value where type like '(struct %s)->%s';" %(struct_type, member))
545 for txt in cur:
546 print "%-30s | %-30s | %s | %s" %(txt[0], txt[1], txt[2], txt[3])
547
548 def rl_too_big(txt):
549 rl = txt_to_rl(txt)
550 ret = ""
551 for idx in range(len(rl)):
552 cur_max = rl[idx][1]
553 if (cur_max > 0xFFFFFFFFFFFFFF):
554 return 1
555
556 return 0
557
558 def rl_has_min_untagged(txt):
559 rl = txt_to_rl(txt)
560 ret = ""
561 for idx in range(len(rl)):
562 cur_min = rl[idx][0]
563 if (cur_min == 0xff80000000000000):
564 return 1
565
566 return 0
567
568 def rl_is_tagged(txt):
569 if not rl_too_big(txt):
570 return 0
571
572 if rl_has_min_untagged(txt):
573 return 0
574
575 return 1
576
577 def rl_is_treat_untagged(txt):
578 if "[u]" in txt:
579 return 1;
580
581 return 0
582
583 def parse_warns_tagged(filename):
584 proc = subprocess.Popen(['cat %s | grep "potentially tagged" | sort | uniq' %(filename)], shell=True, stdout=subprocess.PIPE)
585 while True:
586 line = proc.stdout.readline()
587 if not line:
588 break
589
590 linepos = re.search("([^\s]+)", line).group(1)
591 groupre = re.search("potentially tagged address \(([^,]+), ([^,]+), ([^\)]+)\)", line)
592 groupre.group(1)
593
594 func = groupre.group(1)
595 param = int(groupre.group(2))
596 var = groupre.group(3)
597
598 if ("end" in var or "size" in var or "len" in var):
599 continue
600
601 print "\n%s (func: %s, param: %d:%s) may be caused by:" %(linepos, func, param, var)
602
603 if (param != -1):
604 if not find_tagged(func, param, 0, []):
605 print " %s (param %d) (can't walk call tree)" % (func, param)
606 else:
607 print " %s (variable %s (can't walk call tree)" % (func, var)
608
609 def find_tagged(func, param, caller_call_id, printed):
610
611 callers = {}
612 cur = con.cursor()
613 ptrs = get_function_pointers(func)
614 found = 0
615
616 for ptr in ptrs:
617 cur.execute("select call_id, value from caller_info where function = '%s' and parameter=%d and type=%d" %(ptr, param, type_to_int("DATA_SOURCE")))
618
619 for row in cur:
620 if (row[1][0] == '$'):
621 if row[0] not in callers:
622 callers[row[0]] = {}
623 callers[row[0]]["param"] = int(row[1][1])
624
625 for ptr in ptrs:
626 cur.execute("select caller, call_id, value from caller_info where function = '%s' and parameter=%d and type=%d" %(ptr, param, type_to_int("USER_DATA")))
627
628 for row in cur:
629 if not rl_is_tagged(row[2]):
630 continue
631 if rl_is_treat_untagged(row[2]):
632 continue
633 found = 1
634 if row[1] not in callers:
635 callers[row[1]] = {}
636 if "param" not in callers[row[1]]:
637 line = " %s (param ?) -> %s (param %d)" % (row[0], func, param)
638 if line not in printed:
639 printed.append(line)
640 print line
641 continue
642 if row[0] not in printed:
643 printed.append(row[0])
644 if not find_tagged(row[0], callers[row[1]]["param"], row[1], printed):
645 print " %s (param %d)" % (row[0], param)
646
647 return found
648
649 def trace_callers(func, param):
650 sources = []
651 prev_type = 0
652
653 cur = con.cursor()
654 ptrs = get_function_pointers(func)
655 for ptr in ptrs:
656 cur.execute("select type, caller, value from caller_info where function = '%s' and (type = 0 or type = 1014 or type = 1028) and (parameter = -1 or parameter = %d);" %(ptr, param))
657 for row in cur:
658 data_type = int(row[0])
659 if data_type == 1014:
660 sources.append((row[1], row[2]))
661 elif data_type == 1028:
662 sources.append(("%", row[2])) # hack...
663 elif data_type == 0 and prev_type == 0:
664 sources.append((row[1], ""))
665 prev_type = data_type
666 return sources
667
668 def trace_param_helper(func, param, indent = 0):
669 global printed_funcs
670 if func in printed_funcs:
671 return
672 print "%s%s(param %d)" %(" " * indent, func, param)
673 if func == "too common":
674 return
675 if indent > 20:
676 return
677 printed_funcs.append(func)
678 sources = trace_callers(func, param)
679 for path in sources:
680
681 if len(path[1]) and path[1][0] == '$':
682 p = int(re.findall('\d+', path[1][1:])[0])
683 trace_param_helper(path[0], p, indent + 2)
684 elif len(path[0]) and path[0][0] == '%':
685 print " %s%s" %(" " * indent, path[1])
686 else:
687 print "* %s%s %s" %(" " * (indent - 1), path[0], path[1])
688
689 def trace_param(func, param):
690 global printed_funcs
691 printed_funcs = []
692 print "tracing %s %d" %(func, param)
693 trace_param_helper(func, param)
694
695 def print_locals(filename):
696 cur = con.cursor()
697 cur.execute("select file,data,value from data_info where file = '%s' and type = 8029 and value != 0;" %(filename))
698 for txt in cur:
699 print "%s | %s | %s" %(txt[0], txt[1], txt[2])
700
701 def constraint(struct_type, member):
702 cur = con.cursor()
728 print_fn_ptrs(func)
729 elif sys.argv[1] == "return_states":
730 func = sys.argv[2]
731 print_return_states(func)
732 print "================================================"
733 print_return_implies(func)
734 elif sys.argv[1] == "return_implies":
735 func = sys.argv[2]
736 print_return_implies(func)
737 elif sys.argv[1] == "type_size" or sys.argv[1] == "buf_size":
738 struct_type = sys.argv[2]
739 member = sys.argv[3]
740 print_type_size(struct_type, member)
741 elif sys.argv[1] == "data_info":
742 struct_type = sys.argv[2]
743 member = sys.argv[3]
744 print_data_info(struct_type, member)
745 elif sys.argv[1] == "call_tree":
746 func = sys.argv[2]
747 print_call_tree(func)
748 elif sys.argv[1] == "find_tagged":
749 func = sys.argv[2]
750 param = int(sys.argv[3])
751 find_tagged(func, param, 0, [])
752 elif sys.argv[1] == "parse_warns_tagged":
753 filename = sys.argv[2]
754 parse_warns_tagged(filename)
755 elif sys.argv[1] == "where":
756 if len(sys.argv) == 3:
757 struct_type = "%"
758 member = sys.argv[2]
759 elif len(sys.argv) == 4:
760 struct_type = sys.argv[2]
761 member = sys.argv[3]
762 function_type_value(struct_type, member)
763 elif sys.argv[1] == "local":
764 filename = sys.argv[2]
765 variable = ""
766 if len(sys.argv) == 4:
767 variable = sys.argv[3]
768 local_values(filename, variable)
769 elif sys.argv[1] == "functions":
770 member = sys.argv[2]
771 print_functions(member)
772 elif sys.argv[1] == "trace_param":
773 if len(sys.argv) != 4:
774 usage()
775 func = sys.argv[2]
776 param = int(sys.argv[3])
777 trace_param(func, param)
778 elif sys.argv[1] == "locals":
779 if len(sys.argv) != 3:
780 usage()
781 filename = sys.argv[2]
782 print_locals(filename);
783 elif sys.argv[1] == "constraint":
784 if len(sys.argv) == 3:
785 struct_type = "%"
786 member = sys.argv[2]
787 elif len(sys.argv) == 4:
788 struct_type = sys.argv[2]
789 member = sys.argv[3]
790 constraint(struct_type, member)
791 else:
792 usage()
|