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