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()