smdb: add a "preempt" option
[smatch.git] / smatch_data / db / smdb.py
blob91c0223750c71143a5031e5560655bccf4197f06
1 #!/usr/bin/python3
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 as 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",
99 1044: "FRESH_ALLOC",
100 1047: "TIME",
102 2054: "PREEMPT_ADD",
103 2055: "PREEMPT_SUB",
105 8017: "USER_DATA",
106 9017: "USER_DATA_SET",
107 9018: "USER_PTR",
108 9019: "USER_PTR_SET",
109 8018: "NO_OVERFLOW",
110 8019: "NO_OVERFLOW_SIMPLE",
111 8020: "LOCKED",
112 8021: "UNLOCKED",
113 8046: "RELEASE",
114 9022: "HALF_LOCKED",
115 9023: "LOCK_RESTORED",
116 9024: "KNOWN_LOCKED",
117 9025: "KNOWN_UNLOCKED",
118 8023: "ATOMIC_INC",
119 8024: "ATOMIC_DEC",
120 9027: "REFCOUNT_INC",
121 9028: "REFCOUNT_DEC",
124 def add_range(rl, min_val, max_val):
125 check_next = 0
126 done = 0
127 ret = []
128 idx = 0
130 if len(rl) == 0:
131 return [[min_val, max_val]]
133 for idx in range(len(rl)):
134 cur_min = rl[idx][0]
135 cur_max = rl[idx][1]
137 # we already merged the new range but we might need to change later
138 # ranges if they over lap with more than one
139 if check_next:
140 # join with added range
141 if max_val + 1 == cur_min:
142 ret[len(ret) - 1][1] = cur_max
143 done = 1
144 break
145 # don't overlap
146 if max_val < cur_min:
147 ret.append([cur_min, cur_max])
148 done = 1
149 break
150 # partially overlap
151 if max_val < cur_max:
152 ret[len(ret) - 1][1] = cur_max
153 done = 1
154 break
155 # completely overlap
156 continue
158 # join 2 ranges into one
159 if max_val + 1 == cur_min:
160 ret.append([min_val, cur_max])
161 done = 1
162 break
163 # range is entirely below
164 if max_val < cur_min:
165 ret.append([min_val, max_val])
166 ret.append([cur_min, cur_max])
167 done = 1
168 break
169 # range is partially below
170 if min_val < cur_min:
171 if max_val <= cur_max:
172 ret.append([min_val, cur_max])
173 done = 1
174 break
175 else:
176 ret.append([min_val, max_val])
177 check_next = 1
178 continue
179 # range already included
180 if max_val <= cur_max:
181 ret.append([cur_min, cur_max])
182 done = 1
183 break;
184 # range partially above
185 if min_val <= cur_max:
186 ret.append([cur_min, max_val])
187 check_next = 1
188 continue
189 # join 2 ranges on the other side
190 if min_val - 1 == cur_max:
191 ret.append([cur_min, max_val])
192 check_next = 1
193 continue
194 # range is above
195 ret.append([cur_min, cur_max])
197 if idx + 1 < len(rl): # we hit a break statement
198 ret = ret + rl[idx + 1:]
199 elif done: # we hit a break on the last iteration
200 pass
201 elif not check_next: # it's past the end of the rl
202 ret.append([min_val, max_val])
204 return ret;
206 def rl_union(rl1, rl2):
207 ret = []
208 for r in rl1:
209 ret = add_range(ret, r[0], r[1])
210 for r in rl2:
211 ret = add_range(ret, r[0], r[1])
213 if (rl1 or rl2) and not ret:
214 print("bug: merging %s + %s gives empty" %(rl1, rl2))
216 return ret
218 def txt_to_val(txt):
219 if txt == "s64min":
220 return -(2**63)
221 elif txt == "s32min":
222 return -(2**31)
223 elif txt == "s16min":
224 return -(2**15)
225 elif txt == "s64max":
226 return 2**63 - 1
227 elif txt == "s32max":
228 return 2**31 - 1
229 elif txt == "s16max":
230 return 2**15 - 1
231 elif txt == "u64max":
232 return 2**64 - 1
233 elif txt == "ptr_max":
234 return 2**64 - 1
235 elif txt == "u32max":
236 return 2**32 - 1
237 elif txt == "u16max":
238 return 2**16 - 1
239 else:
240 try:
241 return int(txt)
242 except ValueError:
243 return 0
245 def val_to_txt(val):
246 if val == -(2**63):
247 return "s64min"
248 elif val == -(2**31):
249 return "s32min"
250 elif val == -(2**15):
251 return "s16min"
252 elif val == 2**63 - 1:
253 return "s64max"
254 elif val == 2**31 - 1:
255 return "s32max"
256 elif val == 2**15 - 1:
257 return "s16max"
258 elif val == 2**64 - 1:
259 return "u64max"
260 elif val == 2**32 - 1:
261 return "u32max"
262 elif val == 2**16 - 1:
263 return "u16max"
264 elif val < 0:
265 return "(%d)" %(val)
266 else:
267 return "%d" %(val)
269 def get_next_str(txt):
270 val = ""
271 parsed = 0
273 if txt[0] == '(':
274 parsed += 1
275 for char in txt[1:]:
276 if char == ')':
277 break
278 parsed += 1
279 val = txt[1:parsed]
280 parsed += 1
281 elif txt[0] == 's' or txt[0] == 'u':
282 parsed += 6
283 val = txt[:parsed]
284 else:
285 if txt[0] == '-':
286 parsed += 1
287 for char in txt[parsed:]:
288 if char == '-' or char == '[':
289 break
290 parsed += 1
291 val = txt[:parsed]
292 return [parsed, val]
294 def txt_to_rl(txt):
295 if len(txt) == 0:
296 return []
298 ret = []
299 pairs = txt.split(",")
300 for pair in pairs:
301 cnt, min_str = get_next_str(pair)
302 if cnt == len(pair):
303 max_str = min_str
304 else:
305 cnt, max_str = get_next_str(pair[cnt + 1:])
306 min_val = txt_to_val(min_str)
307 max_val = txt_to_val(max_str)
308 ret.append([min_val, max_val])
310 # Hm... Smatch won't call INT_MAX s32max if the variable is unsigned.
311 # if txt != rl_to_txt(ret):
312 # print("bug: converting: text = %s rl = %s internal = %s" %(txt, rl_to_txt(ret), ret))
314 return ret
316 def rl_to_txt(rl):
317 ret = ""
318 for idx in range(len(rl)):
319 cur_min = rl[idx][0]
320 cur_max = rl[idx][1]
322 if idx != 0:
323 ret += ","
325 if cur_min == cur_max:
326 ret += val_to_txt(cur_min)
327 else:
328 ret += val_to_txt(cur_min)
329 ret += "-"
330 ret += val_to_txt(cur_max)
331 return ret
333 def type_to_str(type_int):
335 t = int(type_int)
336 if t in db_types:
337 return db_types[t]
338 return type_int
340 def type_to_int(type_string):
341 for k in db_types.keys():
342 if db_types[k] == type_string:
343 return k
344 return -1
346 def display_caller_info(printed, cur, param_names):
347 for txt in cur:
348 if not printed:
349 print("file | caller | function | type | parameter | key | value |")
350 printed = 1
352 parameter = int(txt[6])
353 key = txt[7]
354 if len(param_names) and parameter in param_names:
355 key = key.replace("$", param_names[parameter])
357 print("%20s | %20s | %20s |" %(txt[0], txt[1], txt[2]), end = '')
358 print(" %18s |" %(type_to_str(txt[5])), end = '')
359 print(" %2d | %15s | %s" %(parameter, key, txt[8]))
360 return printed
362 def get_caller_info(filename, ptrs, my_type):
363 cur = con.cursor()
364 param_names = get_param_names(filename, func)
365 printed = 0
366 type_filter = ""
367 if my_type != "":
368 type_filter = "and type = %d" %(type_to_int(my_type))
369 for ptr in ptrs:
370 cur.execute("select * from caller_info where function = '%s' %s;" %(ptr, type_filter))
371 printed = display_caller_info(printed, cur, param_names)
373 def print_caller_info(filename, func, my_type = ""):
374 ptrs = get_function_pointers(func)
375 get_caller_info(filename, ptrs, my_type)
377 def merge_values(param_names, vals, cur):
378 for txt in cur:
379 parameter = int(txt[0])
380 name = txt[1]
381 rl = txt_to_rl(txt[2])
382 if parameter in param_names:
383 name = name.replace("$", param_names[parameter])
385 if not parameter in vals:
386 vals[parameter] = {}
388 # the first item on the list is the number of rows. it's incremented
389 # every time we call merge_values().
390 if name in vals[parameter]:
391 vals[parameter][name] = [vals[parameter][name][0] + 1, rl_union(vals[parameter][name][1], rl)]
392 else:
393 vals[parameter][name] = [1, rl]
395 def get_param_names(filename, func):
396 cur = con.cursor()
397 param_names = {}
398 cur.execute("select parameter, value from parameter_name where file = '%s' and function = '%s';" %(filename, func))
399 for txt in cur:
400 parameter = int(txt[0])
401 name = txt[1]
402 param_names[parameter] = name
403 if len(param_names):
404 return param_names
406 cur.execute("select parameter, value from parameter_name where function = '%s';" %(func))
407 for txt in cur:
408 parameter = int(txt[0])
409 name = txt[1]
410 param_names[parameter] = name
411 return param_names
413 def get_caller_count(ptrs):
414 cur = con.cursor()
415 count = 0
416 for ptr in ptrs:
417 cur.execute("select count(distinct(call_id)) from caller_info where function = '%s';" %(ptr))
418 for txt in cur:
419 count += int(txt[0])
420 return count
422 def print_merged_caller_values(filename, func, ptrs, param_names, call_cnt):
423 cur = con.cursor()
424 vals = {}
425 for ptr in ptrs:
426 cur.execute("select parameter, key, value from caller_info where function = '%s' and type = %d;" %(ptr, type_to_int("PARAM_VALUE")))
427 merge_values(param_names, vals, cur);
429 for param in sorted(vals):
430 for name in sorted(vals[param]):
431 if vals[param][name][0] != call_cnt:
432 continue
433 print("%d %s -> %s" %(param, name, rl_to_txt(vals[param][name][1])))
436 def print_unmerged_caller_values(filename, func, ptrs, param_names):
437 cur = con.cursor()
438 for ptr in ptrs:
439 prev = -1
440 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")))
441 for filename, caller, call_id, parameter, name, value in cur:
442 if prev != int(call_id):
443 prev = int(call_id)
445 parameter = int(parameter)
446 if parameter < len(param_names):
447 name = name.replace("$", param_names[parameter])
448 else:
449 name = name.replace("$", "$%d" %(parameter))
451 print("%s | %s | %s | %s" %(filename, caller, name, value))
452 print("==========================")
454 def print_caller_values(filename, func, ptrs):
455 param_names = get_param_names(filename, func)
456 call_cnt = get_caller_count(ptrs)
458 print_merged_caller_values(filename, func, ptrs, param_names, call_cnt)
459 print("==========================")
460 print_unmerged_caller_values(filename, func, ptrs, param_names)
462 def caller_info_values(filename, func):
463 ptrs = get_function_pointers(func)
464 print_caller_values(filename, func, ptrs)
466 def print_return_states(func):
467 cur = con.cursor()
468 cur.execute("select * from return_states where function = '%s';" %(func))
469 count = 0
470 try:
471 for txt in cur:
472 printed = 1
473 if count == 0:
474 print("file | function | return_id | return_value | type | param | key | value |")
475 count += 1
476 print("%s | %s | %2s | %13s" %(txt[0], txt[1], txt[3], txt[4]), end = '')
477 print("| %15s |" %(type_to_str(txt[6])), end = '')
478 print(" %2d | %20s | %20s |" %(txt[7], txt[8], txt[9]))
479 except:
480 print("\n<ERROR parsing: 'select * from return_states where function = '%s';'>\n" %(func))
482 def print_return_implies(func):
483 cur = con.cursor()
484 cur.execute("select * from return_implies where function = '%s';" %(func))
485 count = 0
486 for txt in cur:
487 if not count:
488 print("file | function | type | param | key | value |")
489 count += 1
490 print("%15s | %15s" %(txt[0], txt[1]), end = '')
491 print("| %15s" %(type_to_str(txt[4])), end = '')
492 print("| %3d | %15s | %15s |" %(txt[5], txt[6], txt[7]))
494 def print_type_size(struct_type, member):
495 cur = con.cursor()
496 cur.execute("select * from type_size where type like '(struct %s)->%s';" %(struct_type, member))
497 print("type | size")
498 for txt in cur:
499 print("%-15s | %s" %(txt[0], txt[1]))
501 cur.execute("select * from function_type_size where type like '(struct %s)->%s';" %(struct_type, member))
502 print("file | function | type | size")
503 for txt in cur:
504 print("%-15s | %-15s | %-15s | %s" %(txt[0], txt[1], txt[2], txt[3]))
506 def print_data_info(struct_type, member):
507 cur = con.cursor()
508 cur.execute("select * from data_info where data like '(struct %s)->%s';" %(struct_type, member))
509 print("file | data | type | value")
510 for txt in cur:
511 print("%-15s | %-15s | %-15s | %s" %(txt[0], txt[1], type_to_str(txt[2]), txt[3]))
513 def print_fn_ptrs(func):
514 ptrs = get_function_pointers(func)
515 if not ptrs:
516 return
517 print("%s = " %(func), end = '')
518 print(ptrs)
520 def print_functions(struct, member):
521 cur = con.cursor()
522 if struct:
523 cur.execute("select * from function_ptr where ptr like '(struct %s)->%s';" %(struct, member))
524 elif member.find(" ") >= 0:
525 cur.execute("select * from function_ptr where ptr = '%s';" %(member))
526 else:
527 cur.execute("select * from function_ptr where ptr like '%%->%s';" %(member))
528 print("File | Pointer | Function | Static")
529 for txt in cur:
530 print("%-15s | %-15s | %-15s | %s" %(txt[0], txt[2], txt[1], txt[3]))
532 def get_callers(func, restrict = ""):
533 if restrict == "":
534 restrict = "and type = 0"
535 ret = []
536 cur = con.cursor()
537 ptrs = get_function_pointers(func)
538 for ptr in ptrs:
539 cur.execute("select distinct caller from caller_info where function = '%s' %s;" %(ptr, restrict))
540 for row in cur:
541 ret.append(row[0])
542 return ret
544 printed_funcs = []
545 def call_tree_helper(func, restrict = "", indent = 0):
546 global printed_funcs
547 if func in printed_funcs:
548 return
549 print("%s%s()" %(" " * indent, func))
550 if func == "too common":
551 return
552 if indent > 30:
553 return
554 printed_funcs.append(func)
555 callers = get_callers(func, restrict)
556 if len(callers) >= 20:
557 print("Over 20 callers for %s()" %(func))
558 return
559 for caller in callers:
560 call_tree_helper(caller, restrict, indent + 2)
562 def print_call_tree(func):
563 global printed_funcs
564 printed_funcs = []
565 call_tree_helper(func)
567 def print_preempt_tree(func):
568 global printed_funcs
569 printed_funcs = []
570 call_tree_helper(func, "and type = 2054")
572 def function_type_value(struct_type, member):
573 cur = con.cursor()
574 cur.execute("select * from function_type_value where type like '(struct %s)->%s';" %(struct_type, member))
575 for txt in cur:
576 print("%-30s | %-30s | %s | %s" %(txt[0], txt[1], txt[2], txt[3]))
578 def rl_too_big(txt):
579 rl = txt_to_rl(txt)
580 ret = ""
581 for idx in range(len(rl)):
582 cur_max = rl[idx][1]
583 if (cur_max > 0xFFFFFFFFFFFFFF):
584 return 1
586 return 0
588 def rl_has_min_untagged(txt):
589 rl = txt_to_rl(txt)
590 ret = ""
591 for idx in range(len(rl)):
592 cur_min = rl[idx][0]
593 if (cur_min == 0xff80000000000000):
594 return 1
596 return 0
598 def rl_is_tagged(txt):
599 if not rl_too_big(txt):
600 return 0
602 if rl_has_min_untagged(txt):
603 return 0
605 return 1
607 def rl_is_treat_untagged(txt):
608 if "[u]" in txt:
609 return 1;
611 return 0
613 def parse_warns_tagged(filename):
614 proc = subprocess.Popen(['cat %s | grep "potentially tagged" | sort | uniq' %(filename)], shell=True, stdout=subprocess.PIPE)
615 while True:
616 line = proc.stdout.readline()
617 if not line:
618 break
620 linepos = re.search("([^\s]+)", line).group(1)
621 groupre = re.search("potentially tagged address \(([^,]+), ([^,]+), ([^\)]+)\)", line)
622 groupre.group(1)
624 func = groupre.group(1)
625 param = int(groupre.group(2))
626 var = groupre.group(3)
628 if ("end" in var or "size" in var or "len" in var):
629 return
631 print("\n%s (func: %s, param: %d:%s) may be caused by:" %(linepos, func, param, var))
633 if (param != -1):
634 if not find_tagged(func, param, 0, []):
635 print(" %s (param %d) (can't walk call tree)" % (func, param))
636 else:
637 print(" %s (variable %s (can't walk call tree)" % (func, var))
639 def find_tagged(func, param, caller_call_id, printed):
641 callers = {}
642 cur = con.cursor()
643 ptrs = get_function_pointers(func)
644 found = 0
646 for ptr in ptrs:
647 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")))
649 for row in cur:
650 if (row[1][0] == '$'):
651 if row[0] not in callers:
652 callers[row[0]] = {}
653 callers[row[0]]["param"] = int(row[1][1])
655 for ptr in ptrs:
656 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")))
658 for row in cur:
659 if not rl_is_tagged(row[2]):
660 continue
661 if rl_is_treat_untagged(row[2]):
662 continue
663 found = 1
664 if row[1] not in callers:
665 callers[row[1]] = {}
666 if "param" not in callers[row[1]]:
667 line = " %s (param ?) -> %s (param %d)" % (row[0], func, param)
668 if line not in printed:
669 printed.append(line)
670 print(line)
671 continue
672 if row[0] not in printed:
673 printed.append(row[0])
674 if not find_tagged(row[0], callers[row[1]]["param"], row[1], printed):
675 print(" %s (param %d)" % (row[0], param))
677 return found
679 def trace_callers(func, param):
680 sources = []
681 prev_type = 0
683 cur = con.cursor()
684 ptrs = get_function_pointers(func)
685 for ptr in ptrs:
686 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))
687 for row in cur:
688 data_type = int(row[0])
689 if data_type == 1014:
690 sources.append((row[1], row[2]))
691 elif data_type == 1028:
692 sources.append(("%", row[2])) # hack...
693 elif data_type == 0 and prev_type == 0:
694 sources.append((row[1], ""))
695 prev_type = data_type
696 return sources
698 def trace_param_helper(func, param, indent = 0):
699 global printed_funcs
700 if func in printed_funcs:
701 return
702 print("%s%s(param %d)" %(" " * indent, func, param))
703 if func == "too common":
704 return
705 if indent > 20:
706 return
707 printed_funcs.append(func)
708 sources = trace_callers(func, param)
709 for path in sources:
711 if len(path[1]) and path[1][0] == '$':
712 p = int(re.findall('\d+', path[1][1:])[0])
713 trace_param_helper(path[0], p, indent + 2)
714 elif len(path[0]) and path[0][0] == '%':
715 print(" %s%s" %(" " * indent, path[1]))
716 else:
717 print("* %s%s %s" %(" " * (indent - 1), path[0], path[1]))
719 def trace_param(func, param):
720 global printed_funcs
721 printed_funcs = []
722 print("tracing %s %d" %(func, param))
723 trace_param_helper(func, param)
725 def print_locals(filename):
726 cur = con.cursor()
727 cur.execute("select file,data,value from data_info where file = '%s' and type = 8029 and value != 0;" %(filename))
728 for txt in cur:
729 print("%s | %s | %s" %(txt[0], txt[1], txt[2]))
731 def constraint(struct_type, member):
732 cur = con.cursor()
733 cur.execute("select * from constraints_required where data like '(struct %s)->%s' or bound like '(struct %s)->%s';" %(struct_type, member, struct_type, member))
734 for txt in cur:
735 print("%-30s | %-30s | %s | %s" %(txt[0], txt[1], txt[2], txt[3]))
737 if len(sys.argv) < 2:
738 usage()
740 if len(sys.argv) == 2:
741 func = sys.argv[1]
742 print_caller_info("", func)
743 elif sys.argv[1] == "info":
744 my_type = ""
745 if len(sys.argv) == 4:
746 my_type = sys.argv[3]
747 func = sys.argv[2]
748 print_caller_info("", func, my_type)
749 elif sys.argv[1] == "call_info":
750 if len(sys.argv) != 4:
751 usage()
752 filename = sys.argv[2]
753 func = sys.argv[3]
754 caller_info_values(filename, func)
755 print_caller_info(filename, func)
756 elif sys.argv[1] == "function_ptr" or sys.argv[1] == "fn_ptr":
757 func = sys.argv[2]
758 print_fn_ptrs(func)
759 elif sys.argv[1] == "return_states":
760 func = sys.argv[2]
761 print_return_states(func)
762 print("================================================")
763 print_return_implies(func)
764 elif sys.argv[1] == "return_implies":
765 func = sys.argv[2]
766 print_return_implies(func)
767 elif sys.argv[1] == "type_size" or sys.argv[1] == "buf_size":
768 struct_type = sys.argv[2]
769 member = sys.argv[3]
770 print_type_size(struct_type, member)
771 elif sys.argv[1] == "data_info":
772 struct_type = sys.argv[2]
773 member = sys.argv[3]
774 print_data_info(struct_type, member)
775 elif sys.argv[1] == "call_tree":
776 func = sys.argv[2]
777 print_call_tree(func)
778 elif sys.argv[1] == "preempt":
779 func = sys.argv[2]
780 print_preempt_tree(func)
781 elif sys.argv[1] == "find_tagged":
782 func = sys.argv[2]
783 param = int(sys.argv[3])
784 find_tagged(func, param, 0, [])
785 elif sys.argv[1] == "parse_warns_tagged":
786 filename = sys.argv[2]
787 parse_warns_tagged(filename)
788 elif sys.argv[1] == "where":
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 function_type_value(struct_type, member)
796 elif sys.argv[1] == "local":
797 filename = sys.argv[2]
798 variable = ""
799 if len(sys.argv) == 4:
800 variable = sys.argv[3]
801 local_values(filename, variable)
802 elif sys.argv[1] == "functions":
803 if len(sys.argv) == 4:
804 struct = sys.argv[2]
805 member = sys.argv[3]
806 else:
807 struct = ""
808 member = sys.argv[2]
809 print_functions(struct, member)
810 elif sys.argv[1] == "trace_param":
811 if len(sys.argv) != 4:
812 usage()
813 func = sys.argv[2]
814 param = int(sys.argv[3])
815 trace_param(func, param)
816 elif sys.argv[1] == "locals":
817 if len(sys.argv) != 3:
818 usage()
819 filename = sys.argv[2]
820 print_locals(filename);
821 elif sys.argv[1] == "constraint":
822 if len(sys.argv) == 3:
823 struct_type = "%"
824 member = sys.argv[2]
825 elif len(sys.argv) == 4:
826 struct_type = sys.argv[2]
827 member = sys.argv[3]
828 constraint(struct_type, member)
829 else:
830 usage()