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
  51     function_ptrs = [func]
  52     searched_ptrs = [func]
  53     get_function_pointers_helper(func)
  54     return function_ptrs
  55 
  56 db_types = {   0: "INTERNAL",
  57              101: "PARAM_CLEARED",
  58              103: "PARAM_LIMIT",
  59              104: "PARAM_FILTER",
  60             1001: "PARAM_VALUE",
  61             1002: "BUF_SIZE",
  62             1004: "CAPPED_DATA",
  63             1005: "RETURN_VALUE",
  64             1006: "DEREFERENCE",
  65             1007: "RANGE_CAP",
  66             1008: "LOCK_HELD",
  67             1009: "LOCK_RELEASED",
  68             1010: "ABSOLUTE_LIMITS",
  69             1012: "PARAM_ADD",
  70             1013: "PARAM_FREED",
  71             1014: "DATA_SOURCE",
  72             1015: "FUZZY_MAX",
  73             1016: "STR_LEN",
  74             1017: "ARRAY_LEN",
  75             1018: "CAPABLE",
  76             1019: "NS_CAPABLE",
  77             1022: "TYPE_LINK",
  78             1023: "UNTRACKED_PARAM",
  79             1024: "CULL_PATH",
  80             1025: "PARAM_SET",
  81             1026: "PARAM_USED",
  82             1027: "BYTE_UNITS",
  83             1028: "COMPARE_LIMIT",
  84             1029: "PARAM_COMPARE",
  85             1030: "EXPECTS_TYPE",
  86             1031: "CONSTRAINT",
  87             1032: "PASSES_TYPE",
  88             1033: "CONSTRAINT_REQUIRED",
  89             1034: "BIT_INFO",
  90             1035: "NOSPEC",
  91             1036: "NOSPEC_WB",
  92             1037: "STMT_CNT",
  93             1038: "TERMINATED",
  94             1039: "SLEEP",
  95             1040: "NO_SLEEP_CNT",
  96             1041: "SMALLISH",
  97             1042: "FRESH_MTAG",
  98 
  99             8017: "USER_DATA",
 100             9017: "USER_DATA_SET",
 101             8018: "NO_OVERFLOW",
 102             8019: "NO_OVERFLOW_SIMPLE",
 103             8020: "LOCKED",
 104             8021: "UNLOCKED",
 105             8023: "ATOMIC_INC",
 106             8024: "ATOMIC_DEC",
 107 };
 108 
 109 def add_range(rl, min_val, max_val):
 110     check_next = 0
 111     done = 0
 112     ret = []
 113     idx = 0
 114 
 115     if len(rl) == 0:
 116         return [[min_val, max_val]]
 117 
 118     for idx in range(len(rl)):
 119         cur_min = rl[idx][0]
 120         cur_max = rl[idx][1]
 121 
 122         # we already merged the new range but we might need to change later
 123         # ranges if they over lap with more than one
 124         if check_next:
 125             # join with added range
 126             if max_val + 1 == cur_min:
 127                 ret[len(ret) - 1][1] = cur_max
 128                 done = 1
 129                 break
 130             # don't overlap
 131             if max_val < cur_min:
 132                 ret.append([cur_min, cur_max])
 133                 done = 1
 134                 break
 135             # partially overlap
 136             if max_val < cur_max:
 137                 ret[len(ret) - 1][1] = cur_max
 138                 done = 1
 139                 break
 140             # completely overlap
 141             continue
 142 
 143         # join 2 ranges into one
 144         if max_val + 1 == cur_min:
 145             ret.append([min_val, cur_max])
 146             done = 1
 147             break
 148         # range is entirely below
 149         if max_val < cur_min:
 150             ret.append([min_val, max_val])
 151             ret.append([cur_min, cur_max])
 152             done = 1
 153             break
 154         # range is partially below
 155         if min_val < cur_min:
 156             if max_val <= cur_max:
 157                 ret.append([min_val, cur_max])
 158                 done = 1
 159                 break
 160             else:
 161                 ret.append([min_val, max_val])
 162                 check_next = 1
 163                 continue
 164         # range already included
 165         if max_val <= cur_max:
 166             ret.append([cur_min, cur_max])
 167             done = 1
 168             break;
 169         # range partially above
 170         if min_val <= cur_max:
 171             ret.append([cur_min, max_val])
 172             check_next = 1
 173             continue
 174         # join 2 ranges on the other side
 175         if min_val - 1 == cur_max:
 176             ret.append([cur_min, max_val])
 177             check_next = 1
 178             continue
 179         # range is above
 180         ret.append([cur_min, cur_max])
 181 
 182     if idx + 1 < len(rl):          # we hit a break statement
 183         ret = ret + rl[idx + 1:]
 184     elif done:                     # we hit a break on the last iteration
 185         pass
 186     elif not check_next:           # it's past the end of the rl
 187         ret.append([min_val, max_val])
 188 
 189     return ret;
 190 
 191 def rl_union(rl1, rl2):
 192     ret = []
 193     for r in rl1:
 194         ret = add_range(ret, r[0], r[1])
 195     for r in rl2:
 196         ret = add_range(ret, r[0], r[1])
 197 
 198     if (rl1 or rl2) and not ret:
 199         print "bug: merging %s + %s gives empty" %(rl1, rl2)
 200 
 201     return ret
 202 
 203 def txt_to_val(txt):
 204     if txt == "s64min":
 205         return -(2**63)
 206     elif txt == "s32min":
 207         return -(2**31)
 208     elif txt == "s16min":
 209         return -(2**15)
 210     elif txt == "s64max":
 211         return 2**63 - 1
 212     elif txt == "s32max":
 213         return 2**31 - 1
 214     elif txt == "s16max":
 215         return 2**15 - 1
 216     elif txt == "u64max":
 217         return 2**64 - 1
 218     elif txt == "ptr_max":
 219         return 2**64 - 1
 220     elif txt == "u32max":
 221         return 2**32 - 1
 222     elif txt == "u16max":
 223         return 2**16 - 1
 224     else:
 225         try:
 226             return int(txt)
 227         except ValueError:
 228             return 0
 229 
 230 def val_to_txt(val):
 231     if val == -(2**63):
 232         return "s64min"
 233     elif val == -(2**31):
 234         return "s32min"
 235     elif val == -(2**15):
 236         return "s16min"
 237     elif val == 2**63 - 1:
 238         return "s64max"
 239     elif val == 2**31 - 1:
 240         return "s32max"
 241     elif val == 2**15 - 1:
 242         return "s16max"
 243     elif val == 2**64 - 1:
 244         return "u64max"
 245     elif val == 2**32 - 1:
 246         return "u32max"
 247     elif val == 2**16 - 1:
 248         return "u16max"
 249     elif val < 0:
 250         return "(%d)" %(val)
 251     else:
 252         return "%d" %(val)
 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])
 294 
 295 #    Hm...  Smatch won't call INT_MAX s32max if the variable is unsigned.
 296 #    if txt != rl_to_txt(ret):
 297 #        print "bug: converting: text = %s rl = %s internal = %s" %(txt, rl_to_txt(ret), ret)
 298 
 299     return ret
 300 
 301 def rl_to_txt(rl):
 302     ret = ""
 303     for idx in range(len(rl)):
 304         cur_min = rl[idx][0]
 305         cur_max = rl[idx][1]
 306 
 307         if idx != 0:
 308             ret += ","
 309 
 310         if cur_min == cur_max:
 311             ret += val_to_txt(cur_min)
 312         else:
 313             ret += val_to_txt(cur_min)
 314             ret += "-"
 315             ret += val_to_txt(cur_max)
 316     return ret
 317 
 318 def type_to_str(type_int):
 319 
 320     t = int(type_int)
 321     if db_types.has_key(t):
 322         return db_types[t]
 323     return type_int
 324 
 325 def type_to_int(type_string):
 326     for k in db_types.keys():
 327         if db_types[k] == type_string:
 328             return k
 329     return -1
 330 
 331 def display_caller_info(printed, cur, param_names):
 332     for txt in cur:
 333         if not printed:
 334             print "file | caller | function | type | parameter | key | value |"
 335         printed = 1
 336 
 337         parameter = int(txt[6])
 338         key = txt[7]
 339         if len(param_names) and parameter in param_names:
 340             key = key.replace("$", param_names[parameter])
 341 
 342         print "%20s | %20s | %20s |" %(txt[0], txt[1], txt[2]),
 343         print " %10s |" %(type_to_str(txt[5])),
 344         print " %d | %s | %s" %(parameter, key, txt[8])
 345     return printed
 346 
 347 def get_caller_info(filename, ptrs, my_type):
 348     cur = con.cursor()
 349     param_names = get_param_names(filename, func)
 350     printed = 0
 351     type_filter = ""
 352     if my_type != "":
 353         type_filter = "and type = %d" %(type_to_int(my_type))
 354     for ptr in ptrs:
 355         cur.execute("select * from caller_info where function = '%s' %s;" %(ptr, type_filter))
 356         printed = display_caller_info(printed, cur, param_names)
 357 
 358 def print_caller_info(filename, func, my_type = ""):
 359     ptrs = get_function_pointers(func)
 360     get_caller_info(filename, ptrs, my_type)
 361 
 362 def merge_values(param_names, vals, cur):
 363     for txt in cur:
 364         parameter = int(txt[0])
 365         name = txt[1]
 366         rl = txt_to_rl(txt[2])
 367         if parameter in param_names:
 368             name = name.replace("$", param_names[parameter])
 369 
 370         if not parameter in vals:
 371             vals[parameter] = {}
 372 
 373         # the first item on the list is the number of rows.  it's incremented
 374         # every time we call merge_values().
 375         if name in vals[parameter]:
 376             vals[parameter][name] = [vals[parameter][name][0] + 1, rl_union(vals[parameter][name][1], rl)]
 377         else:
 378             vals[parameter][name] = [1, rl]
 379 
 380 def get_param_names(filename, func):
 381     cur = con.cursor()
 382     param_names = {}
 383     cur.execute("select parameter, value from parameter_name where file = '%s' and function = '%s';" %(filename, func))
 384     for txt in cur:
 385         parameter = int(txt[0])
 386         name = txt[1]
 387         param_names[parameter] = name
 388     if len(param_names):
 389         return param_names
 390 
 391     cur.execute("select parameter, value from parameter_name where function = '%s';" %(func))
 392     for txt in cur:
 393         parameter = int(txt[0])
 394         name = txt[1]
 395         param_names[parameter] = name
 396     return param_names
 397 
 398 def get_caller_count(ptrs):
 399     cur = con.cursor()
 400     count = 0
 401     for ptr in ptrs:
 402         cur.execute("select count(distinct(call_id)) from caller_info where function = '%s';" %(ptr))
 403         for txt in cur:
 404             count += int(txt[0])
 405     return count
 406 
 407 def print_merged_caller_values(filename, func, ptrs, param_names, call_cnt):
 408     cur = con.cursor()
 409     vals = {}
 410     for ptr in ptrs:
 411         cur.execute("select parameter, key, value from caller_info where function = '%s' and type = %d;" %(ptr, type_to_int("PARAM_VALUE")))
 412         merge_values(param_names, vals, cur);
 413 
 414     for param in sorted(vals):
 415         for name in sorted(vals[param]):
 416             if vals[param][name][0] != call_cnt:
 417                 continue
 418             print "%d %s -> %s" %(param, name, rl_to_txt(vals[param][name][1]))
 419 
 420 
 421 def print_unmerged_caller_values(filename, func, ptrs, param_names):
 422     cur = con.cursor()
 423     for ptr in ptrs:
 424         prev = -1
 425         cur.execute("select file, caller, call_id, parameter, key, value from caller_info where function = '%s' and type = %d;" %(ptr, type_to_int("PARAM_VALUE")))
 426         for filename, caller, call_id, parameter, name, value in cur:
 427             if prev != int(call_id):
 428                 prev = int(call_id)
 429 
 430             parameter = int(parameter)
 431             if parameter < len(param_names):
 432                 name = name.replace("$", param_names[parameter])
 433             else:
 434                 name = name.replace("$", "$%d" %(parameter))
 435 
 436             print "%s | %s | %s | %s" %(filename, caller, name, value)
 437         print "=========================="
 438 
 439 def print_caller_values(filename, func, ptrs):
 440     param_names = get_param_names(filename, func)
 441     call_cnt = get_caller_count(ptrs)
 442 
 443     print_merged_caller_values(filename, func, ptrs, param_names, call_cnt)
 444     print "=========================="
 445     print_unmerged_caller_values(filename, func, ptrs, param_names)
 446 
 447 def caller_info_values(filename, func):
 448     ptrs = get_function_pointers(func)
 449     print_caller_values(filename, func, ptrs)
 450 
 451 def print_return_states(func):
 452     cur = con.cursor()
 453     cur.execute("select * from return_states where function = '%s';" %(func))
 454     count = 0
 455     for txt in cur:
 456         printed = 1
 457         if count == 0:
 458             print "file | function | return_id | return_value | type | param | key | value |"
 459         count += 1
 460         print "%s | %s | %2s | %13s" %(txt[0], txt[1], txt[3], txt[4]),
 461         print "| %13s |" %(type_to_str(txt[6])),
 462         print " %2d | %20s | %20s |" %(txt[7], txt[8], txt[9])
 463 
 464 def print_return_implies(func):
 465     cur = con.cursor()
 466     cur.execute("select * from return_implies where function = '%s';" %(func))
 467     count = 0
 468     for txt in cur:
 469         if not count:
 470             print "file | function | type | param | key | value |"
 471         count += 1
 472         print "%15s | %15s" %(txt[0], txt[1]),
 473         print "| %15s" %(type_to_str(txt[4])),
 474         print "| %3d | %s | %15s |" %(txt[5], txt[6], txt[7])
 475 
 476 def print_type_size(struct_type, member):
 477     cur = con.cursor()
 478     cur.execute("select * from type_size where type like '(struct %s)->%s';" %(struct_type, member))
 479     print "type | size"
 480     for txt in cur:
 481         print "%-15s | %s" %(txt[0], txt[1])
 482 
 483     cur.execute("select * from function_type_size where type like '(struct %s)->%s';" %(struct_type, member))
 484     print "file | function | type | size"
 485     for txt in cur:
 486         print "%-15s | %-15s | %-15s | %s" %(txt[0], txt[1], txt[2], txt[3])
 487 
 488 def print_data_info(struct_type, member):
 489     cur = con.cursor()
 490     cur.execute("select * from data_info where data like '(struct %s)->%s';" %(struct_type, member))
 491     print "file | data | type | value"
 492     for txt in cur:
 493         print "%-15s | %-15s | %-15s | %s" %(txt[0], txt[1], type_to_str(txt[2]), txt[3])
 494 
 495 def print_fn_ptrs(func):
 496     ptrs = get_function_pointers(func)
 497     if not ptrs:
 498         return
 499     print "%s = " %(func),
 500     print(ptrs)
 501 
 502 def print_functions(member):
 503     cur = con.cursor()
 504     cur.execute("select * from function_ptr where ptr like '%%->%s';" %(member))
 505     print "File | Pointer | Function | Static"
 506     for txt in cur:
 507         print "%-15s | %-15s | %-15s | %s" %(txt[0], txt[2], txt[1], txt[3])
 508 
 509 def get_callers(func):
 510     ret = []
 511     cur = con.cursor()
 512     ptrs = get_function_pointers(func)
 513     for ptr in ptrs:
 514         cur.execute("select distinct caller from caller_info where function = '%s';" %(ptr))
 515         for row in cur:
 516             ret.append(row[0])
 517     return ret
 518 
 519 printed_funcs = []
 520 def call_tree_helper(func, indent = 0):
 521     global printed_funcs
 522     if func in printed_funcs:
 523         return
 524     print "%s%s()" %(" " * indent, func)
 525     if func == "too common":
 526         return
 527     if indent > 6:
 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()
 703     cur.execute("select * from constraints_required where data like '(struct %s)->%s' or bound like '(struct %s)->%s';" %(struct_type, member, struct_type, member))
 704     for txt in cur:
 705         print "%-30s | %-30s | %s | %s" %(txt[0], txt[1], txt[2], txt[3])
 706 
 707 if len(sys.argv) < 2:
 708     usage()
 709 
 710 if len(sys.argv) == 2:
 711     func = sys.argv[1]
 712     print_caller_info("", func)
 713 elif sys.argv[1] == "info":
 714     my_type = ""
 715     if len(sys.argv) == 4:
 716         my_type = sys.argv[3]
 717     func = sys.argv[2]
 718     print_caller_info("", func, my_type)
 719 elif sys.argv[1] == "call_info":
 720     if len(sys.argv) != 4:
 721         usage()
 722     filename = sys.argv[2]
 723     func = sys.argv[3]
 724     caller_info_values(filename, func)
 725     print_caller_info(filename, func)
 726 elif sys.argv[1] == "function_ptr" or sys.argv[1] == "fn_ptr":
 727     func = sys.argv[2]
 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()