11f5207b7SJohn Levon#!/usr/bin/python 21f5207b7SJohn Levon 31f5207b7SJohn Levon# Copyright (C) 2013 Oracle. 41f5207b7SJohn Levon# 51f5207b7SJohn Levon# Licensed under the Open Software License version 1.1 61f5207b7SJohn Levon 71f5207b7SJohn Levonimport sqlite3 81f5207b7SJohn Levonimport sys 91f5207b7SJohn Levonimport re 10c85f09ccSJohn Levonimport subprocess 111f5207b7SJohn Levon 121f5207b7SJohn Levontry: 131f5207b7SJohn Levon con = sqlite3.connect('smatch_db.sqlite') 141f5207b7SJohn Levonexcept sqlite3.Error, e: 151f5207b7SJohn Levon print "Error %s:" % e.args[0] 161f5207b7SJohn Levon sys.exit(1) 171f5207b7SJohn Levon 181f5207b7SJohn Levondef usage(): 191f5207b7SJohn Levon print "%s" %(sys.argv[0]) 201f5207b7SJohn Levon print "<function> - how a function is called" 21efe51d0cSJohn Levon print "info <type> - how a function is called, filtered by type" 221f5207b7SJohn Levon print "return_states <function> - what a function returns" 231f5207b7SJohn Levon print "call_tree <function> - show the call tree" 241f5207b7SJohn Levon print "where <struct_type> <member> - where a struct member is set" 251f5207b7SJohn Levon print "type_size <struct_type> <member> - how a struct member is allocated" 261f5207b7SJohn Levon print "data_info <struct_type> <member> - information about a given data type" 271f5207b7SJohn Levon print "function_ptr <function> - which function pointers point to this" 281f5207b7SJohn Levon print "trace_param <function> <param> - trace where a parameter came from" 29c85f09ccSJohn Levon print "find_tagged <function> <param> - find the source of a tagged value (arm64)" 30c85f09ccSJohn Levon print "parse_warns_tagged <smatch_warns.txt> - parse warns file for summary of tagged issues (arm64)" 311f5207b7SJohn Levon print "locals <file> - print the local values in a file." 321f5207b7SJohn Levon sys.exit(1) 331f5207b7SJohn Levon 341f5207b7SJohn Levonfunction_ptrs = [] 351f5207b7SJohn Levonsearched_ptrs = [] 361f5207b7SJohn Levondef get_function_pointers_helper(func): 371f5207b7SJohn Levon cur = con.cursor() 381f5207b7SJohn Levon cur.execute("select distinct ptr from function_ptr where function = '%s';" %(func)) 391f5207b7SJohn Levon for row in cur: 401f5207b7SJohn Levon ptr = row[0] 411f5207b7SJohn Levon if ptr in function_ptrs: 421f5207b7SJohn Levon continue 431f5207b7SJohn Levon function_ptrs.append(ptr) 441f5207b7SJohn Levon if not ptr in searched_ptrs: 451f5207b7SJohn Levon searched_ptrs.append(ptr) 461f5207b7SJohn Levon get_function_pointers_helper(ptr) 471f5207b7SJohn Levon 481f5207b7SJohn Levondef get_function_pointers(func): 491f5207b7SJohn Levon global function_ptrs 501f5207b7SJohn Levon global searched_ptrs 511f5207b7SJohn Levon function_ptrs = [func] 521f5207b7SJohn Levon searched_ptrs = [func] 531f5207b7SJohn Levon get_function_pointers_helper(func) 541f5207b7SJohn Levon return function_ptrs 551f5207b7SJohn Levon 561f5207b7SJohn Levondb_types = { 0: "INTERNAL", 571f5207b7SJohn Levon 101: "PARAM_CLEARED", 581f5207b7SJohn Levon 103: "PARAM_LIMIT", 591f5207b7SJohn Levon 104: "PARAM_FILTER", 601f5207b7SJohn Levon 1001: "PARAM_VALUE", 611f5207b7SJohn Levon 1002: "BUF_SIZE", 621f5207b7SJohn Levon 1004: "CAPPED_DATA", 631f5207b7SJohn Levon 1005: "RETURN_VALUE", 641f5207b7SJohn Levon 1006: "DEREFERENCE", 651f5207b7SJohn Levon 1007: "RANGE_CAP", 661f5207b7SJohn Levon 1008: "LOCK_HELD", 671f5207b7SJohn Levon 1009: "LOCK_RELEASED", 681f5207b7SJohn Levon 1010: "ABSOLUTE_LIMITS", 691f5207b7SJohn Levon 1012: "PARAM_ADD", 701f5207b7SJohn Levon 1013: "PARAM_FREED", 711f5207b7SJohn Levon 1014: "DATA_SOURCE", 721f5207b7SJohn Levon 1015: "FUZZY_MAX", 731f5207b7SJohn Levon 1016: "STR_LEN", 741f5207b7SJohn Levon 1017: "ARRAY_LEN", 751f5207b7SJohn Levon 1018: "CAPABLE", 761f5207b7SJohn Levon 1019: "NS_CAPABLE", 77*6523a3aaSJohn Levon 1020: "CONTAINER", 781f5207b7SJohn Levon 1022: "TYPE_LINK", 791f5207b7SJohn Levon 1023: "UNTRACKED_PARAM", 801f5207b7SJohn Levon 1024: "CULL_PATH", 811f5207b7SJohn Levon 1025: "PARAM_SET", 821f5207b7SJohn Levon 1026: "PARAM_USED", 831f5207b7SJohn Levon 1027: "BYTE_UNITS", 841f5207b7SJohn Levon 1028: "COMPARE_LIMIT", 851f5207b7SJohn Levon 1029: "PARAM_COMPARE", 86efe51d0cSJohn Levon 1030: "EXPECTS_TYPE", 87efe51d0cSJohn Levon 1031: "CONSTRAINT", 88efe51d0cSJohn Levon 1032: "PASSES_TYPE", 89efe51d0cSJohn Levon 1033: "CONSTRAINT_REQUIRED", 90efe51d0cSJohn Levon 1034: "BIT_INFO", 91efe51d0cSJohn Levon 1035: "NOSPEC", 92efe51d0cSJohn Levon 1036: "NOSPEC_WB", 93efe51d0cSJohn Levon 1037: "STMT_CNT", 94efe51d0cSJohn Levon 1038: "TERMINATED", 95efe51d0cSJohn Levon 1039: "SLEEP", 96*6523a3aaSJohn Levon 1040: "PREEMPT_CNT", 97efe51d0cSJohn Levon 1041: "SMALLISH", 98efe51d0cSJohn Levon 1042: "FRESH_MTAG", 99efe51d0cSJohn Levon 100efe51d0cSJohn Levon 8017: "USER_DATA", 101efe51d0cSJohn Levon 9017: "USER_DATA_SET", 1021f5207b7SJohn Levon 8018: "NO_OVERFLOW", 1031f5207b7SJohn Levon 8019: "NO_OVERFLOW_SIMPLE", 1041f5207b7SJohn Levon 8020: "LOCKED", 1051f5207b7SJohn Levon 8021: "UNLOCKED", 106*6523a3aaSJohn Levon 9022: "HALF_LOCKED", 107*6523a3aaSJohn Levon 9023: "LOCK_RESTORED", 108*6523a3aaSJohn Levon 9024: "KNOWN_LOCKED", 109*6523a3aaSJohn Levon 9025: "KNOWN_UNLOCKED", 1101f5207b7SJohn Levon 8023: "ATOMIC_INC", 1111f5207b7SJohn Levon 8024: "ATOMIC_DEC", 1121f5207b7SJohn Levon}; 1131f5207b7SJohn Levon 1141f5207b7SJohn Levondef add_range(rl, min_val, max_val): 1151f5207b7SJohn Levon check_next = 0 1161f5207b7SJohn Levon done = 0 1171f5207b7SJohn Levon ret = [] 1181f5207b7SJohn Levon idx = 0 1191f5207b7SJohn Levon 1201f5207b7SJohn Levon if len(rl) == 0: 1211f5207b7SJohn Levon return [[min_val, max_val]] 1221f5207b7SJohn Levon 1231f5207b7SJohn Levon for idx in range(len(rl)): 1241f5207b7SJohn Levon cur_min = rl[idx][0] 1251f5207b7SJohn Levon cur_max = rl[idx][1] 1261f5207b7SJohn Levon 1271f5207b7SJohn Levon # we already merged the new range but we might need to change later 1281f5207b7SJohn Levon # ranges if they over lap with more than one 1291f5207b7SJohn Levon if check_next: 1301f5207b7SJohn Levon # join with added range 1311f5207b7SJohn Levon if max_val + 1 == cur_min: 1321f5207b7SJohn Levon ret[len(ret) - 1][1] = cur_max 1331f5207b7SJohn Levon done = 1 1341f5207b7SJohn Levon break 1351f5207b7SJohn Levon # don't overlap 1361f5207b7SJohn Levon if max_val < cur_min: 1371f5207b7SJohn Levon ret.append([cur_min, cur_max]) 1381f5207b7SJohn Levon done = 1 1391f5207b7SJohn Levon break 1401f5207b7SJohn Levon # partially overlap 1411f5207b7SJohn Levon if max_val < cur_max: 1421f5207b7SJohn Levon ret[len(ret) - 1][1] = cur_max 1431f5207b7SJohn Levon done = 1 1441f5207b7SJohn Levon break 1451f5207b7SJohn Levon # completely overlap 1461f5207b7SJohn Levon continue 1471f5207b7SJohn Levon 1481f5207b7SJohn Levon # join 2 ranges into one 1491f5207b7SJohn Levon if max_val + 1 == cur_min: 1501f5207b7SJohn Levon ret.append([min_val, cur_max]) 1511f5207b7SJohn Levon done = 1 1521f5207b7SJohn Levon break 1531f5207b7SJohn Levon # range is entirely below 1541f5207b7SJohn Levon if max_val < cur_min: 1551f5207b7SJohn Levon ret.append([min_val, max_val]) 1561f5207b7SJohn Levon ret.append([cur_min, cur_max]) 1571f5207b7SJohn Levon done = 1 1581f5207b7SJohn Levon break 1591f5207b7SJohn Levon # range is partially below 1601f5207b7SJohn Levon if min_val < cur_min: 1611f5207b7SJohn Levon if max_val <= cur_max: 1621f5207b7SJohn Levon ret.append([min_val, cur_max]) 1631f5207b7SJohn Levon done = 1 1641f5207b7SJohn Levon break 1651f5207b7SJohn Levon else: 1661f5207b7SJohn Levon ret.append([min_val, max_val]) 1671f5207b7SJohn Levon check_next = 1 1681f5207b7SJohn Levon continue 1691f5207b7SJohn Levon # range already included 1701f5207b7SJohn Levon if max_val <= cur_max: 1711f5207b7SJohn Levon ret.append([cur_min, cur_max]) 1721f5207b7SJohn Levon done = 1 1731f5207b7SJohn Levon break; 1741f5207b7SJohn Levon # range partially above 1751f5207b7SJohn Levon if min_val <= cur_max: 1761f5207b7SJohn Levon ret.append([cur_min, max_val]) 1771f5207b7SJohn Levon check_next = 1 1781f5207b7SJohn Levon continue 1791f5207b7SJohn Levon # join 2 ranges on the other side 1801f5207b7SJohn Levon if min_val - 1 == cur_max: 1811f5207b7SJohn Levon ret.append([cur_min, max_val]) 1821f5207b7SJohn Levon check_next = 1 1831f5207b7SJohn Levon continue 1841f5207b7SJohn Levon # range is above 1851f5207b7SJohn Levon ret.append([cur_min, cur_max]) 1861f5207b7SJohn Levon 1871f5207b7SJohn Levon if idx + 1 < len(rl): # we hit a break statement 1881f5207b7SJohn Levon ret = ret + rl[idx + 1:] 1891f5207b7SJohn Levon elif done: # we hit a break on the last iteration 1901f5207b7SJohn Levon pass 1911f5207b7SJohn Levon elif not check_next: # it's past the end of the rl 1921f5207b7SJohn Levon ret.append([min_val, max_val]) 1931f5207b7SJohn Levon 1941f5207b7SJohn Levon return ret; 1951f5207b7SJohn Levon 1961f5207b7SJohn Levondef rl_union(rl1, rl2): 1971f5207b7SJohn Levon ret = [] 1981f5207b7SJohn Levon for r in rl1: 1991f5207b7SJohn Levon ret = add_range(ret, r[0], r[1]) 2001f5207b7SJohn Levon for r in rl2: 2011f5207b7SJohn Levon ret = add_range(ret, r[0], r[1]) 2021f5207b7SJohn Levon 2031f5207b7SJohn Levon if (rl1 or rl2) and not ret: 2041f5207b7SJohn Levon print "bug: merging %s + %s gives empty" %(rl1, rl2) 2051f5207b7SJohn Levon 2061f5207b7SJohn Levon return ret 2071f5207b7SJohn Levon 2081f5207b7SJohn Levondef txt_to_val(txt): 2091f5207b7SJohn Levon if txt == "s64min": 2101f5207b7SJohn Levon return -(2**63) 2111f5207b7SJohn Levon elif txt == "s32min": 2121f5207b7SJohn Levon return -(2**31) 2131f5207b7SJohn Levon elif txt == "s16min": 2141f5207b7SJohn Levon return -(2**15) 2151f5207b7SJohn Levon elif txt == "s64max": 2161f5207b7SJohn Levon return 2**63 - 1 2171f5207b7SJohn Levon elif txt == "s32max": 2181f5207b7SJohn Levon return 2**31 - 1 2191f5207b7SJohn Levon elif txt == "s16max": 2201f5207b7SJohn Levon return 2**15 - 1 2211f5207b7SJohn Levon elif txt == "u64max": 2221f5207b7SJohn Levon return 2**64 - 1 223efe51d0cSJohn Levon elif txt == "ptr_max": 224efe51d0cSJohn Levon return 2**64 - 1 2251f5207b7SJohn Levon elif txt == "u32max": 2261f5207b7SJohn Levon return 2**32 - 1 2271f5207b7SJohn Levon elif txt == "u16max": 2281f5207b7SJohn Levon return 2**16 - 1 2291f5207b7SJohn Levon else: 2301f5207b7SJohn Levon try: 2311f5207b7SJohn Levon return int(txt) 2321f5207b7SJohn Levon except ValueError: 2331f5207b7SJohn Levon return 0 2341f5207b7SJohn Levon 2351f5207b7SJohn Levondef val_to_txt(val): 2361f5207b7SJohn Levon if val == -(2**63): 2371f5207b7SJohn Levon return "s64min" 2381f5207b7SJohn Levon elif val == -(2**31): 2391f5207b7SJohn Levon return "s32min" 2401f5207b7SJohn Levon elif val == -(2**15): 2411f5207b7SJohn Levon return "s16min" 2421f5207b7SJohn Levon elif val == 2**63 - 1: 2431f5207b7SJohn Levon return "s64max" 2441f5207b7SJohn Levon elif val == 2**31 - 1: 2451f5207b7SJohn Levon return "s32max" 2461f5207b7SJohn Levon elif val == 2**15 - 1: 2471f5207b7SJohn Levon return "s16max" 2481f5207b7SJohn Levon elif val == 2**64 - 1: 2491f5207b7SJohn Levon return "u64max" 2501f5207b7SJohn Levon elif val == 2**32 - 1: 2511f5207b7SJohn Levon return "u32max" 2521f5207b7SJohn Levon elif val == 2**16 - 1: 2531f5207b7SJohn Levon return "u16max" 2541f5207b7SJohn Levon elif val < 0: 2551f5207b7SJohn Levon return "(%d)" %(val) 2561f5207b7SJohn Levon else: 2571f5207b7SJohn Levon return "%d" %(val) 2581f5207b7SJohn Levon 2591f5207b7SJohn Levondef get_next_str(txt): 2601f5207b7SJohn Levon val = "" 2611f5207b7SJohn Levon parsed = 0 2621f5207b7SJohn Levon 2631f5207b7SJohn Levon if txt[0] == '(': 2641f5207b7SJohn Levon parsed += 1 2651f5207b7SJohn Levon for char in txt[1:]: 2661f5207b7SJohn Levon if char == ')': 2671f5207b7SJohn Levon break 2681f5207b7SJohn Levon parsed += 1 2691f5207b7SJohn Levon val = txt[1:parsed] 2701f5207b7SJohn Levon parsed += 1 2711f5207b7SJohn Levon elif txt[0] == 's' or txt[0] == 'u': 2721f5207b7SJohn Levon parsed += 6 2731f5207b7SJohn Levon val = txt[:parsed] 2741f5207b7SJohn Levon else: 2751f5207b7SJohn Levon if txt[0] == '-': 2761f5207b7SJohn Levon parsed += 1 2771f5207b7SJohn Levon for char in txt[parsed:]: 278c85f09ccSJohn Levon if char == '-' or char == '[': 2791f5207b7SJohn Levon break 2801f5207b7SJohn Levon parsed += 1 2811f5207b7SJohn Levon val = txt[:parsed] 2821f5207b7SJohn Levon return [parsed, val] 2831f5207b7SJohn Levon 2841f5207b7SJohn Levondef txt_to_rl(txt): 2851f5207b7SJohn Levon if len(txt) == 0: 2861f5207b7SJohn Levon return [] 2871f5207b7SJohn Levon 2881f5207b7SJohn Levon ret = [] 2891f5207b7SJohn Levon pairs = txt.split(",") 2901f5207b7SJohn Levon for pair in pairs: 2911f5207b7SJohn Levon cnt, min_str = get_next_str(pair) 2921f5207b7SJohn Levon if cnt == len(pair): 2931f5207b7SJohn Levon max_str = min_str 2941f5207b7SJohn Levon else: 2951f5207b7SJohn Levon cnt, max_str = get_next_str(pair[cnt + 1:]) 2961f5207b7SJohn Levon min_val = txt_to_val(min_str) 2971f5207b7SJohn Levon max_val = txt_to_val(max_str) 2981f5207b7SJohn Levon ret.append([min_val, max_val]) 2991f5207b7SJohn Levon 3001f5207b7SJohn Levon# Hm... Smatch won't call INT_MAX s32max if the variable is unsigned. 3011f5207b7SJohn Levon# if txt != rl_to_txt(ret): 3021f5207b7SJohn Levon# print "bug: converting: text = %s rl = %s internal = %s" %(txt, rl_to_txt(ret), ret) 3031f5207b7SJohn Levon 3041f5207b7SJohn Levon return ret 3051f5207b7SJohn Levon 3061f5207b7SJohn Levondef rl_to_txt(rl): 3071f5207b7SJohn Levon ret = "" 3081f5207b7SJohn Levon for idx in range(len(rl)): 3091f5207b7SJohn Levon cur_min = rl[idx][0] 3101f5207b7SJohn Levon cur_max = rl[idx][1] 3111f5207b7SJohn Levon 3121f5207b7SJohn Levon if idx != 0: 3131f5207b7SJohn Levon ret += "," 3141f5207b7SJohn Levon 3151f5207b7SJohn Levon if cur_min == cur_max: 3161f5207b7SJohn Levon ret += val_to_txt(cur_min) 3171f5207b7SJohn Levon else: 3181f5207b7SJohn Levon ret += val_to_txt(cur_min) 3191f5207b7SJohn Levon ret += "-" 3201f5207b7SJohn Levon ret += val_to_txt(cur_max) 3211f5207b7SJohn Levon return ret 3221f5207b7SJohn Levon 3231f5207b7SJohn Levondef type_to_str(type_int): 3241f5207b7SJohn Levon 3251f5207b7SJohn Levon t = int(type_int) 3261f5207b7SJohn Levon if db_types.has_key(t): 3271f5207b7SJohn Levon return db_types[t] 3281f5207b7SJohn Levon return type_int 3291f5207b7SJohn Levon 3301f5207b7SJohn Levondef type_to_int(type_string): 3311f5207b7SJohn Levon for k in db_types.keys(): 3321f5207b7SJohn Levon if db_types[k] == type_string: 3331f5207b7SJohn Levon return k 3341f5207b7SJohn Levon return -1 3351f5207b7SJohn Levon 3361f5207b7SJohn Levondef display_caller_info(printed, cur, param_names): 3371f5207b7SJohn Levon for txt in cur: 3381f5207b7SJohn Levon if not printed: 3391f5207b7SJohn Levon print "file | caller | function | type | parameter | key | value |" 3401f5207b7SJohn Levon printed = 1 3411f5207b7SJohn Levon 3421f5207b7SJohn Levon parameter = int(txt[6]) 3431f5207b7SJohn Levon key = txt[7] 3441f5207b7SJohn Levon if len(param_names) and parameter in param_names: 3451f5207b7SJohn Levon key = key.replace("$", param_names[parameter]) 3461f5207b7SJohn Levon 3471f5207b7SJohn Levon print "%20s | %20s | %20s |" %(txt[0], txt[1], txt[2]), 3481f5207b7SJohn Levon print " %10s |" %(type_to_str(txt[5])), 3491f5207b7SJohn Levon print " %d | %s | %s" %(parameter, key, txt[8]) 3501f5207b7SJohn Levon return printed 3511f5207b7SJohn Levon 3521f5207b7SJohn Levondef get_caller_info(filename, ptrs, my_type): 3531f5207b7SJohn Levon cur = con.cursor() 3541f5207b7SJohn Levon param_names = get_param_names(filename, func) 3551f5207b7SJohn Levon printed = 0 3561f5207b7SJohn Levon type_filter = "" 3571f5207b7SJohn Levon if my_type != "": 3581f5207b7SJohn Levon type_filter = "and type = %d" %(type_to_int(my_type)) 3591f5207b7SJohn Levon for ptr in ptrs: 3601f5207b7SJohn Levon cur.execute("select * from caller_info where function = '%s' %s;" %(ptr, type_filter)) 3611f5207b7SJohn Levon printed = display_caller_info(printed, cur, param_names) 3621f5207b7SJohn Levon 3631f5207b7SJohn Levondef print_caller_info(filename, func, my_type = ""): 3641f5207b7SJohn Levon ptrs = get_function_pointers(func) 3651f5207b7SJohn Levon get_caller_info(filename, ptrs, my_type) 3661f5207b7SJohn Levon 3671f5207b7SJohn Levondef merge_values(param_names, vals, cur): 3681f5207b7SJohn Levon for txt in cur: 3691f5207b7SJohn Levon parameter = int(txt[0]) 3701f5207b7SJohn Levon name = txt[1] 3711f5207b7SJohn Levon rl = txt_to_rl(txt[2]) 3721f5207b7SJohn Levon if parameter in param_names: 3731f5207b7SJohn Levon name = name.replace("$", param_names[parameter]) 3741f5207b7SJohn Levon 3751f5207b7SJohn Levon if not parameter in vals: 3761f5207b7SJohn Levon vals[parameter] = {} 3771f5207b7SJohn Levon 3781f5207b7SJohn Levon # the first item on the list is the number of rows. it's incremented 3791f5207b7SJohn Levon # every time we call merge_values(). 3801f5207b7SJohn Levon if name in vals[parameter]: 3811f5207b7SJohn Levon vals[parameter][name] = [vals[parameter][name][0] + 1, rl_union(vals[parameter][name][1], rl)] 3821f5207b7SJohn Levon else: 3831f5207b7SJohn Levon vals[parameter][name] = [1, rl] 3841f5207b7SJohn Levon 3851f5207b7SJohn Levondef get_param_names(filename, func): 3861f5207b7SJohn Levon cur = con.cursor() 3871f5207b7SJohn Levon param_names = {} 3881f5207b7SJohn Levon cur.execute("select parameter, value from parameter_name where file = '%s' and function = '%s';" %(filename, func)) 3891f5207b7SJohn Levon for txt in cur: 3901f5207b7SJohn Levon parameter = int(txt[0]) 3911f5207b7SJohn Levon name = txt[1] 3921f5207b7SJohn Levon param_names[parameter] = name 3931f5207b7SJohn Levon if len(param_names): 3941f5207b7SJohn Levon return param_names 3951f5207b7SJohn Levon 3961f5207b7SJohn Levon cur.execute("select parameter, value from parameter_name where function = '%s';" %(func)) 3971f5207b7SJohn Levon for txt in cur: 3981f5207b7SJohn Levon parameter = int(txt[0]) 3991f5207b7SJohn Levon name = txt[1] 4001f5207b7SJohn Levon param_names[parameter] = name 4011f5207b7SJohn Levon return param_names 4021f5207b7SJohn Levon 4031f5207b7SJohn Levondef get_caller_count(ptrs): 4041f5207b7SJohn Levon cur = con.cursor() 4051f5207b7SJohn Levon count = 0 4061f5207b7SJohn Levon for ptr in ptrs: 4071f5207b7SJohn Levon cur.execute("select count(distinct(call_id)) from caller_info where function = '%s';" %(ptr)) 4081f5207b7SJohn Levon for txt in cur: 4091f5207b7SJohn Levon count += int(txt[0]) 4101f5207b7SJohn Levon return count 4111f5207b7SJohn Levon 4121f5207b7SJohn Levondef print_merged_caller_values(filename, func, ptrs, param_names, call_cnt): 4131f5207b7SJohn Levon cur = con.cursor() 4141f5207b7SJohn Levon vals = {} 4151f5207b7SJohn Levon for ptr in ptrs: 4161f5207b7SJohn Levon cur.execute("select parameter, key, value from caller_info where function = '%s' and type = %d;" %(ptr, type_to_int("PARAM_VALUE"))) 4171f5207b7SJohn Levon merge_values(param_names, vals, cur); 4181f5207b7SJohn Levon 4191f5207b7SJohn Levon for param in sorted(vals): 4201f5207b7SJohn Levon for name in sorted(vals[param]): 4211f5207b7SJohn Levon if vals[param][name][0] != call_cnt: 4221f5207b7SJohn Levon continue 4231f5207b7SJohn Levon print "%d %s -> %s" %(param, name, rl_to_txt(vals[param][name][1])) 4241f5207b7SJohn Levon 4251f5207b7SJohn Levon 4261f5207b7SJohn Levondef print_unmerged_caller_values(filename, func, ptrs, param_names): 4271f5207b7SJohn Levon cur = con.cursor() 4281f5207b7SJohn Levon for ptr in ptrs: 4291f5207b7SJohn Levon prev = -1 4301f5207b7SJohn Levon 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"))) 4311f5207b7SJohn Levon for filename, caller, call_id, parameter, name, value in cur: 4321f5207b7SJohn Levon if prev != int(call_id): 4331f5207b7SJohn Levon prev = int(call_id) 4341f5207b7SJohn Levon 4351f5207b7SJohn Levon parameter = int(parameter) 4361f5207b7SJohn Levon if parameter < len(param_names): 4371f5207b7SJohn Levon name = name.replace("$", param_names[parameter]) 4381f5207b7SJohn Levon else: 4391f5207b7SJohn Levon name = name.replace("$", "$%d" %(parameter)) 4401f5207b7SJohn Levon 4411f5207b7SJohn Levon print "%s | %s | %s | %s" %(filename, caller, name, value) 4421f5207b7SJohn Levon print "==========================" 4431f5207b7SJohn Levon 4441f5207b7SJohn Levondef print_caller_values(filename, func, ptrs): 4451f5207b7SJohn Levon param_names = get_param_names(filename, func) 4461f5207b7SJohn Levon call_cnt = get_caller_count(ptrs) 4471f5207b7SJohn Levon 4481f5207b7SJohn Levon print_merged_caller_values(filename, func, ptrs, param_names, call_cnt) 4491f5207b7SJohn Levon print "==========================" 4501f5207b7SJohn Levon print_unmerged_caller_values(filename, func, ptrs, param_names) 4511f5207b7SJohn Levon 4521f5207b7SJohn Levondef caller_info_values(filename, func): 4531f5207b7SJohn Levon ptrs = get_function_pointers(func) 4541f5207b7SJohn Levon print_caller_values(filename, func, ptrs) 4551f5207b7SJohn Levon 4561f5207b7SJohn Levondef print_return_states(func): 4571f5207b7SJohn Levon cur = con.cursor() 4581f5207b7SJohn Levon cur.execute("select * from return_states where function = '%s';" %(func)) 4591f5207b7SJohn Levon count = 0 4601f5207b7SJohn Levon for txt in cur: 4611f5207b7SJohn Levon printed = 1 4621f5207b7SJohn Levon if count == 0: 4631f5207b7SJohn Levon print "file | function | return_id | return_value | type | param | key | value |" 4641f5207b7SJohn Levon count += 1 4651f5207b7SJohn Levon print "%s | %s | %2s | %13s" %(txt[0], txt[1], txt[3], txt[4]), 4661f5207b7SJohn Levon print "| %13s |" %(type_to_str(txt[6])), 4671f5207b7SJohn Levon print " %2d | %20s | %20s |" %(txt[7], txt[8], txt[9]) 4681f5207b7SJohn Levon 4691f5207b7SJohn Levondef print_return_implies(func): 4701f5207b7SJohn Levon cur = con.cursor() 4711f5207b7SJohn Levon cur.execute("select * from return_implies where function = '%s';" %(func)) 4721f5207b7SJohn Levon count = 0 4731f5207b7SJohn Levon for txt in cur: 4741f5207b7SJohn Levon if not count: 4751f5207b7SJohn Levon print "file | function | type | param | key | value |" 4761f5207b7SJohn Levon count += 1 4771f5207b7SJohn Levon print "%15s | %15s" %(txt[0], txt[1]), 4781f5207b7SJohn Levon print "| %15s" %(type_to_str(txt[4])), 4791f5207b7SJohn Levon print "| %3d | %s | %15s |" %(txt[5], txt[6], txt[7]) 4801f5207b7SJohn Levon 4811f5207b7SJohn Levondef print_type_size(struct_type, member): 4821f5207b7SJohn Levon cur = con.cursor() 4831f5207b7SJohn Levon cur.execute("select * from type_size where type like '(struct %s)->%s';" %(struct_type, member)) 4841f5207b7SJohn Levon print "type | size" 4851f5207b7SJohn Levon for txt in cur: 4861f5207b7SJohn Levon print "%-15s | %s" %(txt[0], txt[1]) 4871f5207b7SJohn Levon 4881f5207b7SJohn Levon cur.execute("select * from function_type_size where type like '(struct %s)->%s';" %(struct_type, member)) 4891f5207b7SJohn Levon print "file | function | type | size" 4901f5207b7SJohn Levon for txt in cur: 4911f5207b7SJohn Levon print "%-15s | %-15s | %-15s | %s" %(txt[0], txt[1], txt[2], txt[3]) 4921f5207b7SJohn Levon 4931f5207b7SJohn Levondef print_data_info(struct_type, member): 4941f5207b7SJohn Levon cur = con.cursor() 4951f5207b7SJohn Levon cur.execute("select * from data_info where data like '(struct %s)->%s';" %(struct_type, member)) 4961f5207b7SJohn Levon print "file | data | type | value" 4971f5207b7SJohn Levon for txt in cur: 4981f5207b7SJohn Levon print "%-15s | %-15s | %-15s | %s" %(txt[0], txt[1], type_to_str(txt[2]), txt[3]) 4991f5207b7SJohn Levon 5001f5207b7SJohn Levondef print_fn_ptrs(func): 5011f5207b7SJohn Levon ptrs = get_function_pointers(func) 5021f5207b7SJohn Levon if not ptrs: 5031f5207b7SJohn Levon return 5041f5207b7SJohn Levon print "%s = " %(func), 5051f5207b7SJohn Levon print(ptrs) 5061f5207b7SJohn Levon 5071f5207b7SJohn Levondef print_functions(member): 5081f5207b7SJohn Levon cur = con.cursor() 5091f5207b7SJohn Levon cur.execute("select * from function_ptr where ptr like '%%->%s';" %(member)) 5101f5207b7SJohn Levon print "File | Pointer | Function | Static" 5111f5207b7SJohn Levon for txt in cur: 5121f5207b7SJohn Levon print "%-15s | %-15s | %-15s | %s" %(txt[0], txt[2], txt[1], txt[3]) 5131f5207b7SJohn Levon 5141f5207b7SJohn Levondef get_callers(func): 5151f5207b7SJohn Levon ret = [] 5161f5207b7SJohn Levon cur = con.cursor() 5171f5207b7SJohn Levon ptrs = get_function_pointers(func) 5181f5207b7SJohn Levon for ptr in ptrs: 5191f5207b7SJohn Levon cur.execute("select distinct caller from caller_info where function = '%s';" %(ptr)) 5201f5207b7SJohn Levon for row in cur: 5211f5207b7SJohn Levon ret.append(row[0]) 5221f5207b7SJohn Levon return ret 5231f5207b7SJohn Levon 5241f5207b7SJohn Levonprinted_funcs = [] 5251f5207b7SJohn Levondef call_tree_helper(func, indent = 0): 5261f5207b7SJohn Levon global printed_funcs 5271f5207b7SJohn Levon if func in printed_funcs: 5281f5207b7SJohn Levon return 5291f5207b7SJohn Levon print "%s%s()" %(" " * indent, func) 5301f5207b7SJohn Levon if func == "too common": 5311f5207b7SJohn Levon return 5321f5207b7SJohn Levon if indent > 6: 5331f5207b7SJohn Levon return 5341f5207b7SJohn Levon printed_funcs.append(func) 5351f5207b7SJohn Levon callers = get_callers(func) 5361f5207b7SJohn Levon if len(callers) >= 20: 5371f5207b7SJohn Levon print "Over 20 callers for %s()" %(func) 5381f5207b7SJohn Levon return 5391f5207b7SJohn Levon for caller in callers: 5401f5207b7SJohn Levon call_tree_helper(caller, indent + 2) 5411f5207b7SJohn Levon 5421f5207b7SJohn Levondef print_call_tree(func): 5431f5207b7SJohn Levon global printed_funcs 5441f5207b7SJohn Levon printed_funcs = [] 5451f5207b7SJohn Levon call_tree_helper(func) 5461f5207b7SJohn Levon 5471f5207b7SJohn Levondef function_type_value(struct_type, member): 5481f5207b7SJohn Levon cur = con.cursor() 5491f5207b7SJohn Levon cur.execute("select * from function_type_value where type like '(struct %s)->%s';" %(struct_type, member)) 5501f5207b7SJohn Levon for txt in cur: 5511f5207b7SJohn Levon print "%-30s | %-30s | %s | %s" %(txt[0], txt[1], txt[2], txt[3]) 5521f5207b7SJohn Levon 553c85f09ccSJohn Levondef rl_too_big(txt): 554c85f09ccSJohn Levon rl = txt_to_rl(txt) 555c85f09ccSJohn Levon ret = "" 556c85f09ccSJohn Levon for idx in range(len(rl)): 557c85f09ccSJohn Levon cur_max = rl[idx][1] 558c85f09ccSJohn Levon if (cur_max > 0xFFFFFFFFFFFFFF): 559c85f09ccSJohn Levon return 1 560c85f09ccSJohn Levon 561c85f09ccSJohn Levon return 0 562c85f09ccSJohn Levon 563c85f09ccSJohn Levondef rl_has_min_untagged(txt): 564c85f09ccSJohn Levon rl = txt_to_rl(txt) 565c85f09ccSJohn Levon ret = "" 566c85f09ccSJohn Levon for idx in range(len(rl)): 567c85f09ccSJohn Levon cur_min = rl[idx][0] 568c85f09ccSJohn Levon if (cur_min == 0xff80000000000000): 569c85f09ccSJohn Levon return 1 570c85f09ccSJohn Levon 571c85f09ccSJohn Levon return 0 572c85f09ccSJohn Levon 573c85f09ccSJohn Levondef rl_is_tagged(txt): 574c85f09ccSJohn Levon if not rl_too_big(txt): 575c85f09ccSJohn Levon return 0 576c85f09ccSJohn Levon 577c85f09ccSJohn Levon if rl_has_min_untagged(txt): 578c85f09ccSJohn Levon return 0 579c85f09ccSJohn Levon 580c85f09ccSJohn Levon return 1 581c85f09ccSJohn Levon 582c85f09ccSJohn Levondef rl_is_treat_untagged(txt): 583c85f09ccSJohn Levon if "[u]" in txt: 584c85f09ccSJohn Levon return 1; 585c85f09ccSJohn Levon 586c85f09ccSJohn Levon return 0 587c85f09ccSJohn Levon 588c85f09ccSJohn Levondef parse_warns_tagged(filename): 589c85f09ccSJohn Levon proc = subprocess.Popen(['cat %s | grep "potentially tagged" | sort | uniq' %(filename)], shell=True, stdout=subprocess.PIPE) 590c85f09ccSJohn Levon while True: 591c85f09ccSJohn Levon line = proc.stdout.readline() 592c85f09ccSJohn Levon if not line: 593c85f09ccSJohn Levon break 594c85f09ccSJohn Levon 595c85f09ccSJohn Levon linepos = re.search("([^\s]+)", line).group(1) 596c85f09ccSJohn Levon groupre = re.search("potentially tagged address \(([^,]+), ([^,]+), ([^\)]+)\)", line) 597c85f09ccSJohn Levon groupre.group(1) 598c85f09ccSJohn Levon 599c85f09ccSJohn Levon func = groupre.group(1) 600c85f09ccSJohn Levon param = int(groupre.group(2)) 601c85f09ccSJohn Levon var = groupre.group(3) 602c85f09ccSJohn Levon 603c85f09ccSJohn Levon if ("end" in var or "size" in var or "len" in var): 604c85f09ccSJohn Levon continue 605c85f09ccSJohn Levon 606c85f09ccSJohn Levon print "\n%s (func: %s, param: %d:%s) may be caused by:" %(linepos, func, param, var) 607c85f09ccSJohn Levon 608c85f09ccSJohn Levon if (param != -1): 609c85f09ccSJohn Levon if not find_tagged(func, param, 0, []): 610c85f09ccSJohn Levon print " %s (param %d) (can't walk call tree)" % (func, param) 611c85f09ccSJohn Levon else: 612c85f09ccSJohn Levon print " %s (variable %s (can't walk call tree)" % (func, var) 613c85f09ccSJohn Levon 614c85f09ccSJohn Levondef find_tagged(func, param, caller_call_id, printed): 615c85f09ccSJohn Levon 616c85f09ccSJohn Levon callers = {} 617c85f09ccSJohn Levon cur = con.cursor() 618c85f09ccSJohn Levon ptrs = get_function_pointers(func) 619c85f09ccSJohn Levon found = 0 620c85f09ccSJohn Levon 621c85f09ccSJohn Levon for ptr in ptrs: 622c85f09ccSJohn Levon 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"))) 623c85f09ccSJohn Levon 624c85f09ccSJohn Levon for row in cur: 625c85f09ccSJohn Levon if (row[1][0] == '$'): 626c85f09ccSJohn Levon if row[0] not in callers: 627c85f09ccSJohn Levon callers[row[0]] = {} 628c85f09ccSJohn Levon callers[row[0]]["param"] = int(row[1][1]) 629c85f09ccSJohn Levon 630c85f09ccSJohn Levon for ptr in ptrs: 631c85f09ccSJohn Levon 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"))) 632c85f09ccSJohn Levon 633c85f09ccSJohn Levon for row in cur: 634c85f09ccSJohn Levon if not rl_is_tagged(row[2]): 635c85f09ccSJohn Levon continue 636c85f09ccSJohn Levon if rl_is_treat_untagged(row[2]): 637c85f09ccSJohn Levon continue 638c85f09ccSJohn Levon found = 1 639c85f09ccSJohn Levon if row[1] not in callers: 640c85f09ccSJohn Levon callers[row[1]] = {} 641c85f09ccSJohn Levon if "param" not in callers[row[1]]: 642c85f09ccSJohn Levon line = " %s (param ?) -> %s (param %d)" % (row[0], func, param) 643c85f09ccSJohn Levon if line not in printed: 644c85f09ccSJohn Levon printed.append(line) 645c85f09ccSJohn Levon print line 646c85f09ccSJohn Levon continue 647c85f09ccSJohn Levon if row[0] not in printed: 648c85f09ccSJohn Levon printed.append(row[0]) 649c85f09ccSJohn Levon if not find_tagged(row[0], callers[row[1]]["param"], row[1], printed): 650c85f09ccSJohn Levon print " %s (param %d)" % (row[0], param) 651c85f09ccSJohn Levon 652c85f09ccSJohn Levon return found 653c85f09ccSJohn Levon 6541f5207b7SJohn Levondef trace_callers(func, param): 6551f5207b7SJohn Levon sources = [] 6561f5207b7SJohn Levon prev_type = 0 6571f5207b7SJohn Levon 6581f5207b7SJohn Levon cur = con.cursor() 6591f5207b7SJohn Levon ptrs = get_function_pointers(func) 6601f5207b7SJohn Levon for ptr in ptrs: 6611f5207b7SJohn Levon 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)) 6621f5207b7SJohn Levon for row in cur: 6631f5207b7SJohn Levon data_type = int(row[0]) 6641f5207b7SJohn Levon if data_type == 1014: 6651f5207b7SJohn Levon sources.append((row[1], row[2])) 6661f5207b7SJohn Levon elif data_type == 1028: 6671f5207b7SJohn Levon sources.append(("%", row[2])) # hack... 6681f5207b7SJohn Levon elif data_type == 0 and prev_type == 0: 6691f5207b7SJohn Levon sources.append((row[1], "")) 6701f5207b7SJohn Levon prev_type = data_type 6711f5207b7SJohn Levon return sources 6721f5207b7SJohn Levon 6731f5207b7SJohn Levondef trace_param_helper(func, param, indent = 0): 6741f5207b7SJohn Levon global printed_funcs 6751f5207b7SJohn Levon if func in printed_funcs: 6761f5207b7SJohn Levon return 6771f5207b7SJohn Levon print "%s%s(param %d)" %(" " * indent, func, param) 6781f5207b7SJohn Levon if func == "too common": 6791f5207b7SJohn Levon return 6801f5207b7SJohn Levon if indent > 20: 6811f5207b7SJohn Levon return 6821f5207b7SJohn Levon printed_funcs.append(func) 6831f5207b7SJohn Levon sources = trace_callers(func, param) 6841f5207b7SJohn Levon for path in sources: 6851f5207b7SJohn Levon 686c85f09ccSJohn Levon if len(path[1]) and path[1][0] == '$': 687c85f09ccSJohn Levon p = int(re.findall('\d+', path[1][1:])[0]) 6881f5207b7SJohn Levon trace_param_helper(path[0], p, indent + 2) 6891f5207b7SJohn Levon elif len(path[0]) and path[0][0] == '%': 6901f5207b7SJohn Levon print " %s%s" %(" " * indent, path[1]) 6911f5207b7SJohn Levon else: 6921f5207b7SJohn Levon print "* %s%s %s" %(" " * (indent - 1), path[0], path[1]) 6931f5207b7SJohn Levon 6941f5207b7SJohn Levondef trace_param(func, param): 6951f5207b7SJohn Levon global printed_funcs 6961f5207b7SJohn Levon printed_funcs = [] 6971f5207b7SJohn Levon print "tracing %s %d" %(func, param) 6981f5207b7SJohn Levon trace_param_helper(func, param) 6991f5207b7SJohn Levon 7001f5207b7SJohn Levondef print_locals(filename): 7011f5207b7SJohn Levon cur = con.cursor() 7021f5207b7SJohn Levon cur.execute("select file,data,value from data_info where file = '%s' and type = 8029 and value != 0;" %(filename)) 7031f5207b7SJohn Levon for txt in cur: 7041f5207b7SJohn Levon print "%s | %s | %s" %(txt[0], txt[1], txt[2]) 7051f5207b7SJohn Levon 7061f5207b7SJohn Levondef constraint(struct_type, member): 7071f5207b7SJohn Levon cur = con.cursor() 7081f5207b7SJohn Levon cur.execute("select * from constraints_required where data like '(struct %s)->%s' or bound like '(struct %s)->%s';" %(struct_type, member, struct_type, member)) 7091f5207b7SJohn Levon for txt in cur: 7101f5207b7SJohn Levon print "%-30s | %-30s | %s | %s" %(txt[0], txt[1], txt[2], txt[3]) 7111f5207b7SJohn Levon 7121f5207b7SJohn Levonif len(sys.argv) < 2: 7131f5207b7SJohn Levon usage() 7141f5207b7SJohn Levon 7151f5207b7SJohn Levonif len(sys.argv) == 2: 7161f5207b7SJohn Levon func = sys.argv[1] 7171f5207b7SJohn Levon print_caller_info("", func) 718efe51d0cSJohn Levonelif sys.argv[1] == "info": 719efe51d0cSJohn Levon my_type = "" 720efe51d0cSJohn Levon if len(sys.argv) == 4: 721efe51d0cSJohn Levon my_type = sys.argv[3] 722efe51d0cSJohn Levon func = sys.argv[2] 723efe51d0cSJohn Levon print_caller_info("", func, my_type) 7241f5207b7SJohn Levonelif sys.argv[1] == "call_info": 7251f5207b7SJohn Levon if len(sys.argv) != 4: 7261f5207b7SJohn Levon usage() 7271f5207b7SJohn Levon filename = sys.argv[2] 7281f5207b7SJohn Levon func = sys.argv[3] 7291f5207b7SJohn Levon caller_info_values(filename, func) 7301f5207b7SJohn Levon print_caller_info(filename, func) 7311f5207b7SJohn Levonelif sys.argv[1] == "function_ptr" or sys.argv[1] == "fn_ptr": 7321f5207b7SJohn Levon func = sys.argv[2] 7331f5207b7SJohn Levon print_fn_ptrs(func) 7341f5207b7SJohn Levonelif sys.argv[1] == "return_states": 7351f5207b7SJohn Levon func = sys.argv[2] 7361f5207b7SJohn Levon print_return_states(func) 7371f5207b7SJohn Levon print "================================================" 7381f5207b7SJohn Levon print_return_implies(func) 7391f5207b7SJohn Levonelif sys.argv[1] == "return_implies": 7401f5207b7SJohn Levon func = sys.argv[2] 7411f5207b7SJohn Levon print_return_implies(func) 7421f5207b7SJohn Levonelif sys.argv[1] == "type_size" or sys.argv[1] == "buf_size": 7431f5207b7SJohn Levon struct_type = sys.argv[2] 7441f5207b7SJohn Levon member = sys.argv[3] 7451f5207b7SJohn Levon print_type_size(struct_type, member) 7461f5207b7SJohn Levonelif sys.argv[1] == "data_info": 7471f5207b7SJohn Levon struct_type = sys.argv[2] 7481f5207b7SJohn Levon member = sys.argv[3] 7491f5207b7SJohn Levon print_data_info(struct_type, member) 7501f5207b7SJohn Levonelif sys.argv[1] == "call_tree": 7511f5207b7SJohn Levon func = sys.argv[2] 7521f5207b7SJohn Levon print_call_tree(func) 753c85f09ccSJohn Levonelif sys.argv[1] == "find_tagged": 754c85f09ccSJohn Levon func = sys.argv[2] 755c85f09ccSJohn Levon param = int(sys.argv[3]) 756c85f09ccSJohn Levon find_tagged(func, param, 0, []) 757c85f09ccSJohn Levonelif sys.argv[1] == "parse_warns_tagged": 758c85f09ccSJohn Levon filename = sys.argv[2] 759c85f09ccSJohn Levon parse_warns_tagged(filename) 7601f5207b7SJohn Levonelif sys.argv[1] == "where": 7611f5207b7SJohn Levon if len(sys.argv) == 3: 7621f5207b7SJohn Levon struct_type = "%" 7631f5207b7SJohn Levon member = sys.argv[2] 7641f5207b7SJohn Levon elif len(sys.argv) == 4: 7651f5207b7SJohn Levon struct_type = sys.argv[2] 7661f5207b7SJohn Levon member = sys.argv[3] 7671f5207b7SJohn Levon function_type_value(struct_type, member) 7681f5207b7SJohn Levonelif sys.argv[1] == "local": 7691f5207b7SJohn Levon filename = sys.argv[2] 7701f5207b7SJohn Levon variable = "" 7711f5207b7SJohn Levon if len(sys.argv) == 4: 7721f5207b7SJohn Levon variable = sys.argv[3] 7731f5207b7SJohn Levon local_values(filename, variable) 7741f5207b7SJohn Levonelif sys.argv[1] == "functions": 7751f5207b7SJohn Levon member = sys.argv[2] 7761f5207b7SJohn Levon print_functions(member) 7771f5207b7SJohn Levonelif sys.argv[1] == "trace_param": 7781f5207b7SJohn Levon if len(sys.argv) != 4: 7791f5207b7SJohn Levon usage() 7801f5207b7SJohn Levon func = sys.argv[2] 7811f5207b7SJohn Levon param = int(sys.argv[3]) 7821f5207b7SJohn Levon trace_param(func, param) 7831f5207b7SJohn Levonelif sys.argv[1] == "locals": 7841f5207b7SJohn Levon if len(sys.argv) != 3: 7851f5207b7SJohn Levon usage() 7861f5207b7SJohn Levon filename = sys.argv[2] 7871f5207b7SJohn Levon print_locals(filename); 7881f5207b7SJohn Levonelif sys.argv[1] == "constraint": 7891f5207b7SJohn Levon if len(sys.argv) == 3: 7901f5207b7SJohn Levon struct_type = "%" 7911f5207b7SJohn Levon member = sys.argv[2] 7921f5207b7SJohn Levon elif len(sys.argv) == 4: 7931f5207b7SJohn Levon struct_type = sys.argv[2] 7941f5207b7SJohn Levon member = sys.argv[3] 7951f5207b7SJohn Levon constraint(struct_type, member) 7961f5207b7SJohn Levonelse: 7971f5207b7SJohn Levon usage() 798