Print this page
11972 resync smatch
   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()