1#!/usr/bin/python 2 3# Copyright (C) 2013 Oracle. 4# 5# Licensed under the Open Software License version 1.1 6 7import sqlite3 8import sys 9import re 10import subprocess 11 12try: 13 con = sqlite3.connect('smatch_db.sqlite') 14except sqlite3.Error, e: 15 print "Error %s:" % e.args[0] 16 sys.exit(1) 17 18def 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 34function_ptrs = [] 35searched_ptrs = [] 36def 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 48def 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 56db_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 1020: "CONTAINER", 78 1022: "TYPE_LINK", 79 1023: "UNTRACKED_PARAM", 80 1024: "CULL_PATH", 81 1025: "PARAM_SET", 82 1026: "PARAM_USED", 83 1027: "BYTE_UNITS", 84 1028: "COMPARE_LIMIT", 85 1029: "PARAM_COMPARE", 86 1030: "EXPECTS_TYPE", 87 1031: "CONSTRAINT", 88 1032: "PASSES_TYPE", 89 1033: "CONSTRAINT_REQUIRED", 90 1034: "BIT_INFO", 91 1035: "NOSPEC", 92 1036: "NOSPEC_WB", 93 1037: "STMT_CNT", 94 1038: "TERMINATED", 95 1039: "SLEEP", 96 1040: "PREEMPT_CNT", 97 1041: "SMALLISH", 98 1042: "FRESH_MTAG", 99 100 8017: "USER_DATA", 101 9017: "USER_DATA_SET", 102 8018: "NO_OVERFLOW", 103 8019: "NO_OVERFLOW_SIMPLE", 104 8020: "LOCKED", 105 8021: "UNLOCKED", 106 9022: "HALF_LOCKED", 107 9023: "LOCK_RESTORED", 108 9024: "KNOWN_LOCKED", 109 9025: "KNOWN_UNLOCKED", 110 8023: "ATOMIC_INC", 111 8024: "ATOMIC_DEC", 112}; 113 114def add_range(rl, min_val, max_val): 115 check_next = 0 116 done = 0 117 ret = [] 118 idx = 0 119 120 if len(rl) == 0: 121 return [[min_val, max_val]] 122 123 for idx in range(len(rl)): 124 cur_min = rl[idx][0] 125 cur_max = rl[idx][1] 126 127 # we already merged the new range but we might need to change later 128 # ranges if they over lap with more than one 129 if check_next: 130 # join with added range 131 if max_val + 1 == cur_min: 132 ret[len(ret) - 1][1] = cur_max 133 done = 1 134 break 135 # don't overlap 136 if max_val < cur_min: 137 ret.append([cur_min, cur_max]) 138 done = 1 139 break 140 # partially overlap 141 if max_val < cur_max: 142 ret[len(ret) - 1][1] = cur_max 143 done = 1 144 break 145 # completely overlap 146 continue 147 148 # join 2 ranges into one 149 if max_val + 1 == cur_min: 150 ret.append([min_val, cur_max]) 151 done = 1 152 break 153 # range is entirely below 154 if max_val < cur_min: 155 ret.append([min_val, max_val]) 156 ret.append([cur_min, cur_max]) 157 done = 1 158 break 159 # range is partially below 160 if min_val < cur_min: 161 if max_val <= cur_max: 162 ret.append([min_val, cur_max]) 163 done = 1 164 break 165 else: 166 ret.append([min_val, max_val]) 167 check_next = 1 168 continue 169 # range already included 170 if max_val <= cur_max: 171 ret.append([cur_min, cur_max]) 172 done = 1 173 break; 174 # range partially above 175 if min_val <= cur_max: 176 ret.append([cur_min, max_val]) 177 check_next = 1 178 continue 179 # join 2 ranges on the other side 180 if min_val - 1 == cur_max: 181 ret.append([cur_min, max_val]) 182 check_next = 1 183 continue 184 # range is above 185 ret.append([cur_min, cur_max]) 186 187 if idx + 1 < len(rl): # we hit a break statement 188 ret = ret + rl[idx + 1:] 189 elif done: # we hit a break on the last iteration 190 pass 191 elif not check_next: # it's past the end of the rl 192 ret.append([min_val, max_val]) 193 194 return ret; 195 196def rl_union(rl1, rl2): 197 ret = [] 198 for r in rl1: 199 ret = add_range(ret, r[0], r[1]) 200 for r in rl2: 201 ret = add_range(ret, r[0], r[1]) 202 203 if (rl1 or rl2) and not ret: 204 print "bug: merging %s + %s gives empty" %(rl1, rl2) 205 206 return ret 207 208def txt_to_val(txt): 209 if txt == "s64min": 210 return -(2**63) 211 elif txt == "s32min": 212 return -(2**31) 213 elif txt == "s16min": 214 return -(2**15) 215 elif txt == "s64max": 216 return 2**63 - 1 217 elif txt == "s32max": 218 return 2**31 - 1 219 elif txt == "s16max": 220 return 2**15 - 1 221 elif txt == "u64max": 222 return 2**64 - 1 223 elif txt == "ptr_max": 224 return 2**64 - 1 225 elif txt == "u32max": 226 return 2**32 - 1 227 elif txt == "u16max": 228 return 2**16 - 1 229 else: 230 try: 231 return int(txt) 232 except ValueError: 233 return 0 234 235def val_to_txt(val): 236 if val == -(2**63): 237 return "s64min" 238 elif val == -(2**31): 239 return "s32min" 240 elif val == -(2**15): 241 return "s16min" 242 elif val == 2**63 - 1: 243 return "s64max" 244 elif val == 2**31 - 1: 245 return "s32max" 246 elif val == 2**15 - 1: 247 return "s16max" 248 elif val == 2**64 - 1: 249 return "u64max" 250 elif val == 2**32 - 1: 251 return "u32max" 252 elif val == 2**16 - 1: 253 return "u16max" 254 elif val < 0: 255 return "(%d)" %(val) 256 else: 257 return "%d" %(val) 258 259def get_next_str(txt): 260 val = "" 261 parsed = 0 262 263 if txt[0] == '(': 264 parsed += 1 265 for char in txt[1:]: 266 if char == ')': 267 break 268 parsed += 1 269 val = txt[1:parsed] 270 parsed += 1 271 elif txt[0] == 's' or txt[0] == 'u': 272 parsed += 6 273 val = txt[:parsed] 274 else: 275 if txt[0] == '-': 276 parsed += 1 277 for char in txt[parsed:]: 278 if char == '-' or char == '[': 279 break 280 parsed += 1 281 val = txt[:parsed] 282 return [parsed, val] 283 284def txt_to_rl(txt): 285 if len(txt) == 0: 286 return [] 287 288 ret = [] 289 pairs = txt.split(",") 290 for pair in pairs: 291 cnt, min_str = get_next_str(pair) 292 if cnt == len(pair): 293 max_str = min_str 294 else: 295 cnt, max_str = get_next_str(pair[cnt + 1:]) 296 min_val = txt_to_val(min_str) 297 max_val = txt_to_val(max_str) 298 ret.append([min_val, max_val]) 299 300# Hm... Smatch won't call INT_MAX s32max if the variable is unsigned. 301# if txt != rl_to_txt(ret): 302# print "bug: converting: text = %s rl = %s internal = %s" %(txt, rl_to_txt(ret), ret) 303 304 return ret 305 306def rl_to_txt(rl): 307 ret = "" 308 for idx in range(len(rl)): 309 cur_min = rl[idx][0] 310 cur_max = rl[idx][1] 311 312 if idx != 0: 313 ret += "," 314 315 if cur_min == cur_max: 316 ret += val_to_txt(cur_min) 317 else: 318 ret += val_to_txt(cur_min) 319 ret += "-" 320 ret += val_to_txt(cur_max) 321 return ret 322 323def type_to_str(type_int): 324 325 t = int(type_int) 326 if db_types.has_key(t): 327 return db_types[t] 328 return type_int 329 330def type_to_int(type_string): 331 for k in db_types.keys(): 332 if db_types[k] == type_string: 333 return k 334 return -1 335 336def display_caller_info(printed, cur, param_names): 337 for txt in cur: 338 if not printed: 339 print "file | caller | function | type | parameter | key | value |" 340 printed = 1 341 342 parameter = int(txt[6]) 343 key = txt[7] 344 if len(param_names) and parameter in param_names: 345 key = key.replace("$", param_names[parameter]) 346 347 print "%20s | %20s | %20s |" %(txt[0], txt[1], txt[2]), 348 print " %10s |" %(type_to_str(txt[5])), 349 print " %d | %s | %s" %(parameter, key, txt[8]) 350 return printed 351 352def get_caller_info(filename, ptrs, my_type): 353 cur = con.cursor() 354 param_names = get_param_names(filename, func) 355 printed = 0 356 type_filter = "" 357 if my_type != "": 358 type_filter = "and type = %d" %(type_to_int(my_type)) 359 for ptr in ptrs: 360 cur.execute("select * from caller_info where function = '%s' %s;" %(ptr, type_filter)) 361 printed = display_caller_info(printed, cur, param_names) 362 363def print_caller_info(filename, func, my_type = ""): 364 ptrs = get_function_pointers(func) 365 get_caller_info(filename, ptrs, my_type) 366 367def merge_values(param_names, vals, cur): 368 for txt in cur: 369 parameter = int(txt[0]) 370 name = txt[1] 371 rl = txt_to_rl(txt[2]) 372 if parameter in param_names: 373 name = name.replace("$", param_names[parameter]) 374 375 if not parameter in vals: 376 vals[parameter] = {} 377 378 # the first item on the list is the number of rows. it's incremented 379 # every time we call merge_values(). 380 if name in vals[parameter]: 381 vals[parameter][name] = [vals[parameter][name][0] + 1, rl_union(vals[parameter][name][1], rl)] 382 else: 383 vals[parameter][name] = [1, rl] 384 385def get_param_names(filename, func): 386 cur = con.cursor() 387 param_names = {} 388 cur.execute("select parameter, value from parameter_name where file = '%s' and function = '%s';" %(filename, func)) 389 for txt in cur: 390 parameter = int(txt[0]) 391 name = txt[1] 392 param_names[parameter] = name 393 if len(param_names): 394 return param_names 395 396 cur.execute("select parameter, value from parameter_name where function = '%s';" %(func)) 397 for txt in cur: 398 parameter = int(txt[0]) 399 name = txt[1] 400 param_names[parameter] = name 401 return param_names 402 403def get_caller_count(ptrs): 404 cur = con.cursor() 405 count = 0 406 for ptr in ptrs: 407 cur.execute("select count(distinct(call_id)) from caller_info where function = '%s';" %(ptr)) 408 for txt in cur: 409 count += int(txt[0]) 410 return count 411 412def print_merged_caller_values(filename, func, ptrs, param_names, call_cnt): 413 cur = con.cursor() 414 vals = {} 415 for ptr in ptrs: 416 cur.execute("select parameter, key, value from caller_info where function = '%s' and type = %d;" %(ptr, type_to_int("PARAM_VALUE"))) 417 merge_values(param_names, vals, cur); 418 419 for param in sorted(vals): 420 for name in sorted(vals[param]): 421 if vals[param][name][0] != call_cnt: 422 continue 423 print "%d %s -> %s" %(param, name, rl_to_txt(vals[param][name][1])) 424 425 426def print_unmerged_caller_values(filename, func, ptrs, param_names): 427 cur = con.cursor() 428 for ptr in ptrs: 429 prev = -1 430 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"))) 431 for filename, caller, call_id, parameter, name, value in cur: 432 if prev != int(call_id): 433 prev = int(call_id) 434 435 parameter = int(parameter) 436 if parameter < len(param_names): 437 name = name.replace("$", param_names[parameter]) 438 else: 439 name = name.replace("$", "$%d" %(parameter)) 440 441 print "%s | %s | %s | %s" %(filename, caller, name, value) 442 print "==========================" 443 444def print_caller_values(filename, func, ptrs): 445 param_names = get_param_names(filename, func) 446 call_cnt = get_caller_count(ptrs) 447 448 print_merged_caller_values(filename, func, ptrs, param_names, call_cnt) 449 print "==========================" 450 print_unmerged_caller_values(filename, func, ptrs, param_names) 451 452def caller_info_values(filename, func): 453 ptrs = get_function_pointers(func) 454 print_caller_values(filename, func, ptrs) 455 456def print_return_states(func): 457 cur = con.cursor() 458 cur.execute("select * from return_states where function = '%s';" %(func)) 459 count = 0 460 for txt in cur: 461 printed = 1 462 if count == 0: 463 print "file | function | return_id | return_value | type | param | key | value |" 464 count += 1 465 print "%s | %s | %2s | %13s" %(txt[0], txt[1], txt[3], txt[4]), 466 print "| %13s |" %(type_to_str(txt[6])), 467 print " %2d | %20s | %20s |" %(txt[7], txt[8], txt[9]) 468 469def print_return_implies(func): 470 cur = con.cursor() 471 cur.execute("select * from return_implies where function = '%s';" %(func)) 472 count = 0 473 for txt in cur: 474 if not count: 475 print "file | function | type | param | key | value |" 476 count += 1 477 print "%15s | %15s" %(txt[0], txt[1]), 478 print "| %15s" %(type_to_str(txt[4])), 479 print "| %3d | %s | %15s |" %(txt[5], txt[6], txt[7]) 480 481def print_type_size(struct_type, member): 482 cur = con.cursor() 483 cur.execute("select * from type_size where type like '(struct %s)->%s';" %(struct_type, member)) 484 print "type | size" 485 for txt in cur: 486 print "%-15s | %s" %(txt[0], txt[1]) 487 488 cur.execute("select * from function_type_size where type like '(struct %s)->%s';" %(struct_type, member)) 489 print "file | function | type | size" 490 for txt in cur: 491 print "%-15s | %-15s | %-15s | %s" %(txt[0], txt[1], txt[2], txt[3]) 492 493def print_data_info(struct_type, member): 494 cur = con.cursor() 495 cur.execute("select * from data_info where data like '(struct %s)->%s';" %(struct_type, member)) 496 print "file | data | type | value" 497 for txt in cur: 498 print "%-15s | %-15s | %-15s | %s" %(txt[0], txt[1], type_to_str(txt[2]), txt[3]) 499 500def print_fn_ptrs(func): 501 ptrs = get_function_pointers(func) 502 if not ptrs: 503 return 504 print "%s = " %(func), 505 print(ptrs) 506 507def print_functions(member): 508 cur = con.cursor() 509 cur.execute("select * from function_ptr where ptr like '%%->%s';" %(member)) 510 print "File | Pointer | Function | Static" 511 for txt in cur: 512 print "%-15s | %-15s | %-15s | %s" %(txt[0], txt[2], txt[1], txt[3]) 513 514def get_callers(func): 515 ret = [] 516 cur = con.cursor() 517 ptrs = get_function_pointers(func) 518 for ptr in ptrs: 519 cur.execute("select distinct caller from caller_info where function = '%s';" %(ptr)) 520 for row in cur: 521 ret.append(row[0]) 522 return ret 523 524printed_funcs = [] 525def call_tree_helper(func, indent = 0): 526 global printed_funcs 527 if func in printed_funcs: 528 return 529 print "%s%s()" %(" " * indent, func) 530 if func == "too common": 531 return 532 if indent > 6: 533 return 534 printed_funcs.append(func) 535 callers = get_callers(func) 536 if len(callers) >= 20: 537 print "Over 20 callers for %s()" %(func) 538 return 539 for caller in callers: 540 call_tree_helper(caller, indent + 2) 541 542def print_call_tree(func): 543 global printed_funcs 544 printed_funcs = [] 545 call_tree_helper(func) 546 547def function_type_value(struct_type, member): 548 cur = con.cursor() 549 cur.execute("select * from function_type_value where type like '(struct %s)->%s';" %(struct_type, member)) 550 for txt in cur: 551 print "%-30s | %-30s | %s | %s" %(txt[0], txt[1], txt[2], txt[3]) 552 553def rl_too_big(txt): 554 rl = txt_to_rl(txt) 555 ret = "" 556 for idx in range(len(rl)): 557 cur_max = rl[idx][1] 558 if (cur_max > 0xFFFFFFFFFFFFFF): 559 return 1 560 561 return 0 562 563def rl_has_min_untagged(txt): 564 rl = txt_to_rl(txt) 565 ret = "" 566 for idx in range(len(rl)): 567 cur_min = rl[idx][0] 568 if (cur_min == 0xff80000000000000): 569 return 1 570 571 return 0 572 573def rl_is_tagged(txt): 574 if not rl_too_big(txt): 575 return 0 576 577 if rl_has_min_untagged(txt): 578 return 0 579 580 return 1 581 582def rl_is_treat_untagged(txt): 583 if "[u]" in txt: 584 return 1; 585 586 return 0 587 588def parse_warns_tagged(filename): 589 proc = subprocess.Popen(['cat %s | grep "potentially tagged" | sort | uniq' %(filename)], shell=True, stdout=subprocess.PIPE) 590 while True: 591 line = proc.stdout.readline() 592 if not line: 593 break 594 595 linepos = re.search("([^\s]+)", line).group(1) 596 groupre = re.search("potentially tagged address \(([^,]+), ([^,]+), ([^\)]+)\)", line) 597 groupre.group(1) 598 599 func = groupre.group(1) 600 param = int(groupre.group(2)) 601 var = groupre.group(3) 602 603 if ("end" in var or "size" in var or "len" in var): 604 continue 605 606 print "\n%s (func: %s, param: %d:%s) may be caused by:" %(linepos, func, param, var) 607 608 if (param != -1): 609 if not find_tagged(func, param, 0, []): 610 print " %s (param %d) (can't walk call tree)" % (func, param) 611 else: 612 print " %s (variable %s (can't walk call tree)" % (func, var) 613 614def find_tagged(func, param, caller_call_id, printed): 615 616 callers = {} 617 cur = con.cursor() 618 ptrs = get_function_pointers(func) 619 found = 0 620 621 for ptr in ptrs: 622 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"))) 623 624 for row in cur: 625 if (row[1][0] == '$'): 626 if row[0] not in callers: 627 callers[row[0]] = {} 628 callers[row[0]]["param"] = int(row[1][1]) 629 630 for ptr in ptrs: 631 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"))) 632 633 for row in cur: 634 if not rl_is_tagged(row[2]): 635 continue 636 if rl_is_treat_untagged(row[2]): 637 continue 638 found = 1 639 if row[1] not in callers: 640 callers[row[1]] = {} 641 if "param" not in callers[row[1]]: 642 line = " %s (param ?) -> %s (param %d)" % (row[0], func, param) 643 if line not in printed: 644 printed.append(line) 645 print line 646 continue 647 if row[0] not in printed: 648 printed.append(row[0]) 649 if not find_tagged(row[0], callers[row[1]]["param"], row[1], printed): 650 print " %s (param %d)" % (row[0], param) 651 652 return found 653 654def trace_callers(func, param): 655 sources = [] 656 prev_type = 0 657 658 cur = con.cursor() 659 ptrs = get_function_pointers(func) 660 for ptr in ptrs: 661 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)) 662 for row in cur: 663 data_type = int(row[0]) 664 if data_type == 1014: 665 sources.append((row[1], row[2])) 666 elif data_type == 1028: 667 sources.append(("%", row[2])) # hack... 668 elif data_type == 0 and prev_type == 0: 669 sources.append((row[1], "")) 670 prev_type = data_type 671 return sources 672 673def trace_param_helper(func, param, indent = 0): 674 global printed_funcs 675 if func in printed_funcs: 676 return 677 print "%s%s(param %d)" %(" " * indent, func, param) 678 if func == "too common": 679 return 680 if indent > 20: 681 return 682 printed_funcs.append(func) 683 sources = trace_callers(func, param) 684 for path in sources: 685 686 if len(path[1]) and path[1][0] == '$': 687 p = int(re.findall('\d+', path[1][1:])[0]) 688 trace_param_helper(path[0], p, indent + 2) 689 elif len(path[0]) and path[0][0] == '%': 690 print " %s%s" %(" " * indent, path[1]) 691 else: 692 print "* %s%s %s" %(" " * (indent - 1), path[0], path[1]) 693 694def trace_param(func, param): 695 global printed_funcs 696 printed_funcs = [] 697 print "tracing %s %d" %(func, param) 698 trace_param_helper(func, param) 699 700def print_locals(filename): 701 cur = con.cursor() 702 cur.execute("select file,data,value from data_info where file = '%s' and type = 8029 and value != 0;" %(filename)) 703 for txt in cur: 704 print "%s | %s | %s" %(txt[0], txt[1], txt[2]) 705 706def constraint(struct_type, member): 707 cur = con.cursor() 708 cur.execute("select * from constraints_required where data like '(struct %s)->%s' or bound like '(struct %s)->%s';" %(struct_type, member, struct_type, member)) 709 for txt in cur: 710 print "%-30s | %-30s | %s | %s" %(txt[0], txt[1], txt[2], txt[3]) 711 712if len(sys.argv) < 2: 713 usage() 714 715if len(sys.argv) == 2: 716 func = sys.argv[1] 717 print_caller_info("", func) 718elif sys.argv[1] == "info": 719 my_type = "" 720 if len(sys.argv) == 4: 721 my_type = sys.argv[3] 722 func = sys.argv[2] 723 print_caller_info("", func, my_type) 724elif sys.argv[1] == "call_info": 725 if len(sys.argv) != 4: 726 usage() 727 filename = sys.argv[2] 728 func = sys.argv[3] 729 caller_info_values(filename, func) 730 print_caller_info(filename, func) 731elif sys.argv[1] == "function_ptr" or sys.argv[1] == "fn_ptr": 732 func = sys.argv[2] 733 print_fn_ptrs(func) 734elif sys.argv[1] == "return_states": 735 func = sys.argv[2] 736 print_return_states(func) 737 print "================================================" 738 print_return_implies(func) 739elif sys.argv[1] == "return_implies": 740 func = sys.argv[2] 741 print_return_implies(func) 742elif sys.argv[1] == "type_size" or sys.argv[1] == "buf_size": 743 struct_type = sys.argv[2] 744 member = sys.argv[3] 745 print_type_size(struct_type, member) 746elif sys.argv[1] == "data_info": 747 struct_type = sys.argv[2] 748 member = sys.argv[3] 749 print_data_info(struct_type, member) 750elif sys.argv[1] == "call_tree": 751 func = sys.argv[2] 752 print_call_tree(func) 753elif sys.argv[1] == "find_tagged": 754 func = sys.argv[2] 755 param = int(sys.argv[3]) 756 find_tagged(func, param, 0, []) 757elif sys.argv[1] == "parse_warns_tagged": 758 filename = sys.argv[2] 759 parse_warns_tagged(filename) 760elif sys.argv[1] == "where": 761 if len(sys.argv) == 3: 762 struct_type = "%" 763 member = sys.argv[2] 764 elif len(sys.argv) == 4: 765 struct_type = sys.argv[2] 766 member = sys.argv[3] 767 function_type_value(struct_type, member) 768elif sys.argv[1] == "local": 769 filename = sys.argv[2] 770 variable = "" 771 if len(sys.argv) == 4: 772 variable = sys.argv[3] 773 local_values(filename, variable) 774elif sys.argv[1] == "functions": 775 member = sys.argv[2] 776 print_functions(member) 777elif sys.argv[1] == "trace_param": 778 if len(sys.argv) != 4: 779 usage() 780 func = sys.argv[2] 781 param = int(sys.argv[3]) 782 trace_param(func, param) 783elif sys.argv[1] == "locals": 784 if len(sys.argv) != 3: 785 usage() 786 filename = sys.argv[2] 787 print_locals(filename); 788elif sys.argv[1] == "constraint": 789 if len(sys.argv) == 3: 790 struct_type = "%" 791 member = sys.argv[2] 792 elif len(sys.argv) == 4: 793 struct_type = sys.argv[2] 794 member = sys.argv[3] 795 constraint(struct_type, member) 796else: 797 usage() 798