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 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
114 def 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
196 def 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
208 def 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
235 def 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
259 def 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
284 def 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
306 def 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
323 def 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
330 def 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
336 def 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
352 def 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
363 def print_caller_info(filename, func, my_type = ""):
364 ptrs = get_function_pointers(func)
365 get_caller_info(filename, ptrs, my_type)
366
367 def 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
385 def 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
403 def 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
412 def 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
426 def 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
444 def 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
452 def caller_info_values(filename, func):
453 ptrs = get_function_pointers(func)
454 print_caller_values(filename, func, ptrs)
455
456 def 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
469 def 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
481 def 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
493 def 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
500 def print_fn_ptrs(func):
501 ptrs = get_function_pointers(func)
502 if not ptrs:
503 return
504 print "%s = " %(func),
505 print(ptrs)
506
507 def 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
514 def 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
524 printed_funcs = []
525 def 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
542 def print_call_tree(func):
543 global printed_funcs
544 printed_funcs = []
545 call_tree_helper(func)
546
547 def 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
553 def 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
563 def 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
573 def 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
582 def rl_is_treat_untagged(txt):
583 if "[u]" in txt:
584 return 1;
585
586 return 0
587
588 def 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
614 def 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
654 def 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
673 def 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
694 def 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
700 def 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
706 def 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
712 if len(sys.argv) < 2:
713 usage()
714
715 if len(sys.argv) == 2:
716 func = sys.argv[1]
717 print_caller_info("", func)
718 elif 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)
724 elif 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)
731 elif sys.argv[1] == "function_ptr" or sys.argv[1] == "fn_ptr":
732 func = sys.argv[2]
733 print_fn_ptrs(func)
734 elif sys.argv[1] == "return_states":
735 func = sys.argv[2]
736 print_return_states(func)
737 print "================================================"
738 print_return_implies(func)
739 elif sys.argv[1] == "return_implies":
740 func = sys.argv[2]
741 print_return_implies(func)
742 elif 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)
746 elif sys.argv[1] == "data_info":
747 struct_type = sys.argv[2]
748 member = sys.argv[3]
749 print_data_info(struct_type, member)
750 elif sys.argv[1] == "call_tree":
751 func = sys.argv[2]
752 print_call_tree(func)
753 elif sys.argv[1] == "find_tagged":
754 func = sys.argv[2]
755 param = int(sys.argv[3])
756 find_tagged(func, param, 0, [])
757 elif sys.argv[1] == "parse_warns_tagged":
758 filename = sys.argv[2]
759 parse_warns_tagged(filename)
760 elif 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)
768 elif 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)
774 elif sys.argv[1] == "functions":
775 member = sys.argv[2]
776 print_functions(member)
777 elif 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)
783 elif sys.argv[1] == "locals":
784 if len(sys.argv) != 3:
785 usage()
786 filename = sys.argv[2]
787 print_locals(filename);
788 elif 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)
796 else:
797 usage()