param_key: fix container of when no struct member is referenced
[smatch.git] / smatch_data / db / smdb.py
blobc982848f188d9afa51ca15e2f05512f9abe7fd85
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
11 import io
13 try:
14 con = sqlite3.connect('smatch_db.sqlite')
15 except sqlite3.Error as e:
16 print("Error %s:" % e.args[0])
17 sys.exit(1)
19 def usage():
20 print("%s" % (sys.argv[0]))
21 print("<function> - how a function is called")
22 print("info <type> - how a function is called, filtered by type")
23 print("return_states <function> - what a function returns")
24 print("call_tree <function> - show the call tree")
25 print("where <struct_type> <member> - where a struct member is set")
26 print("type_size <struct_type> <member> - how a struct member is allocated")
27 print("data_info <struct_type> <member> - information about a given data type")
28 print("function_ptr <function> - which function pointers point to this")
29 print("trace_param <function> <param> - trace where a parameter came from")
30 print("find_tagged <function> <param> - find the source of a tagged value (arm64)")
31 print("parse_warns_tagged <smatch_warns.txt> - parse warns file for summary of tagged issues (arm64)")
32 print("locals <file> - print the local values in a file.")
33 sys.exit(1)
35 function_ptrs = []
36 searched_ptrs = []
37 def get_function_pointers_helper(func):
38 cur = con.cursor()
39 cur.execute("select distinct ptr from function_ptr where function = '%s';" %(func))
40 for row in cur:
41 ptr = row[0]
42 if ptr in function_ptrs:
43 continue
44 function_ptrs.append(ptr)
45 if not ptr in searched_ptrs:
46 searched_ptrs.append(ptr)
47 get_function_pointers_helper(ptr)
49 def get_function_pointers(func):
50 global function_ptrs
51 global searched_ptrs
52 function_ptrs = [func]
53 searched_ptrs = [func]
54 get_function_pointers_helper(func)
55 return function_ptrs
57 db_types = { 0: "INTERNAL",
58 103: "PARAM_LIMIT",
59 104: "PARAM_FILTER",
60 501: "BUF_CLEARED",
61 1001: "PARAM_VALUE",
62 1002: "BUF_SIZE",
63 1004: "CAPPED_DATA",
64 1005: "RETURN_VALUE",
65 1006: "DEREFERENCE",
66 1007: "RANGE_CAP",
67 1008: "LOCK_HELD",
68 1009: "LOCK_RELEASED",
69 1010: "ABSOLUTE_LIMITS",
70 1012: "PARAM_ADD",
71 1013: "PARAM_FREED",
72 1014: "DATA_SOURCE",
73 1015: "FUZZY_MAX",
74 1016: "STR_LEN",
75 1017: "ARRAY_LEN",
76 1018: "CAPABLE",
77 1019: "NS_CAPABLE",
78 1020: "CONTAINER",
79 1022: "TYPE_LINK",
80 1023: "UNTRACKED_PARAM",
81 1024: "CULL_PATH",
82 1025: "PARAM_SET",
83 1026: "PARAM_USED",
84 1027: "BYTE_UNITS",
85 1028: "COMPARE_LIMIT",
86 1029: "PARAM_COMPARE",
87 1030: "EXPECTS_TYPE",
88 1031: "CONSTRAINT",
89 1032: "PASSES_TYPE",
90 1033: "CONSTRAINT_REQUIRED",
91 1034: "BIT_INFO",
92 1035: "NOSPEC",
93 1036: "NOSPEC_WB",
94 1037: "STMT_CNT",
95 1038: "TERMINATED",
96 1039: "SLEEP",
97 1040: "PREEMPT_CNT",
98 1041: "SMALLISH",
99 1042: "FRESH_MTAG",
100 1044: "FRESH_ALLOC",
101 1047: "TIME",
103 2054: "PREEMPT_ADD",
104 2055: "PREEMPT_SUB",
106 8017: "USER_DATA",
107 9017: "USER_DATA_SET",
108 9018: "USER_PTR",
109 9019: "USER_PTR_SET",
110 8018: "NO_OVERFLOW",
111 8019: "NO_OVERFLOW_SIMPLE",
112 8020: "LOCKED",
113 8021: "UNLOCKED",
114 8046: "RELEASE",
115 9022: "HALF_LOCKED",
116 9023: "LOCK_RESTORED",
117 9024: "KNOWN_LOCKED",
118 9025: "KNOWN_UNLOCKED",
119 8023: "ATOMIC_INC",
120 8024: "ATOMIC_DEC",
121 9027: "REFCOUNT_INC",
122 9028: "REFCOUNT_DEC",
125 def add_range(rl, min_val, max_val):
126 check_next = 0
127 done = 0
128 ret = []
129 idx = 0
131 if len(rl) == 0:
132 return [[min_val, max_val]]
134 for idx in range(len(rl)):
135 cur_min = rl[idx][0]
136 cur_max = rl[idx][1]
138 # we already merged the new range but we might need to change later
139 # ranges if they over lap with more than one
140 if check_next:
141 # join with added range
142 if max_val + 1 == cur_min:
143 ret[len(ret) - 1][1] = cur_max
144 done = 1
145 break
146 # don't overlap
147 if max_val < cur_min:
148 ret.append([cur_min, cur_max])
149 done = 1
150 break
151 # partially overlap
152 if max_val < cur_max:
153 ret[len(ret) - 1][1] = cur_max
154 done = 1
155 break
156 # completely overlap
157 continue
159 # join 2 ranges into one
160 if max_val + 1 == cur_min:
161 ret.append([min_val, cur_max])
162 done = 1
163 break
164 # range is entirely below
165 if max_val < cur_min:
166 ret.append([min_val, max_val])
167 ret.append([cur_min, cur_max])
168 done = 1
169 break
170 # range is partially below
171 if min_val < cur_min:
172 if max_val <= cur_max:
173 ret.append([min_val, cur_max])
174 done = 1
175 break
176 else:
177 ret.append([min_val, max_val])
178 check_next = 1
179 continue
180 # range already included
181 if max_val <= cur_max:
182 ret.append([cur_min, cur_max])
183 done = 1
184 break;
185 # range partially above
186 if min_val <= cur_max:
187 ret.append([cur_min, max_val])
188 check_next = 1
189 continue
190 # join 2 ranges on the other side
191 if min_val - 1 == cur_max:
192 ret.append([cur_min, max_val])
193 check_next = 1
194 continue
195 # range is above
196 ret.append([cur_min, cur_max])
198 if idx + 1 < len(rl): # we hit a break statement
199 ret = ret + rl[idx + 1:]
200 elif done: # we hit a break on the last iteration
201 pass
202 elif not check_next: # it's past the end of the rl
203 ret.append([min_val, max_val])
205 return ret;
207 def rl_union(rl1, rl2):
208 ret = []
209 for r in rl1:
210 ret = add_range(ret, r[0], r[1])
211 for r in rl2:
212 ret = add_range(ret, r[0], r[1])
214 if (rl1 or rl2) and not ret:
215 print("bug: merging %s + %s gives empty" %(rl1, rl2))
217 return ret
219 def txt_to_val(txt):
220 if txt == "s64min":
221 return -(2**63)
222 elif txt == "s32min":
223 return -(2**31)
224 elif txt == "s16min":
225 return -(2**15)
226 elif txt == "s64max":
227 return 2**63 - 1
228 elif txt == "s32max":
229 return 2**31 - 1
230 elif txt == "s16max":
231 return 2**15 - 1
232 elif txt == "u64max":
233 return 2**64 - 1
234 elif txt == "ptr_max":
235 return 2**64 - 1
236 elif txt == "u32max":
237 return 2**32 - 1
238 elif txt == "u16max":
239 return 2**16 - 1
240 else:
241 try:
242 return int(txt)
243 except ValueError:
244 return 0
246 def val_to_txt(val):
247 if val == -(2**63):
248 return "s64min"
249 elif val == -(2**31):
250 return "s32min"
251 elif val == -(2**15):
252 return "s16min"
253 elif val == 2**63 - 1:
254 return "s64max"
255 elif val == 2**31 - 1:
256 return "s32max"
257 elif val == 2**15 - 1:
258 return "s16max"
259 elif val == 2**64 - 1:
260 return "u64max"
261 elif val == 2**32 - 1:
262 return "u32max"
263 elif val == 2**16 - 1:
264 return "u16max"
265 elif val < 0:
266 return "(%d)" %(val)
267 else:
268 return "%d" %(val)
270 def get_next_str(txt):
271 val = ""
272 parsed = 0
274 if txt[0] == '(':
275 parsed += 1
276 for char in txt[1:]:
277 if char == ')':
278 break
279 parsed += 1
280 val = txt[1:parsed]
281 parsed += 1
282 elif txt[0] == 's' or txt[0] == 'u':
283 parsed += 6
284 val = txt[:parsed]
285 else:
286 if txt[0] == '-':
287 parsed += 1
288 for char in txt[parsed:]:
289 if char == '-' or char == '[':
290 break
291 parsed += 1
292 val = txt[:parsed]
293 return [parsed, val]
295 def txt_to_rl(txt):
296 if len(txt) == 0:
297 return []
299 ret = []
300 pairs = txt.split(",")
301 for pair in pairs:
302 cnt, min_str = get_next_str(pair)
303 if cnt == len(pair):
304 max_str = min_str
305 else:
306 cnt, max_str = get_next_str(pair[cnt + 1:])
307 min_val = txt_to_val(min_str)
308 max_val = txt_to_val(max_str)
309 ret.append([min_val, max_val])
311 # Hm... Smatch won't call INT_MAX s32max if the variable is unsigned.
312 # if txt != rl_to_txt(ret):
313 # print("bug: converting: text = %s rl = %s internal = %s" %(txt, rl_to_txt(ret), ret))
315 return ret
317 def rl_to_txt(rl):
318 ret = ""
319 for idx in range(len(rl)):
320 cur_min = rl[idx][0]
321 cur_max = rl[idx][1]
323 if idx != 0:
324 ret += ","
326 if cur_min == cur_max:
327 ret += val_to_txt(cur_min)
328 else:
329 ret += val_to_txt(cur_min)
330 ret += "-"
331 ret += val_to_txt(cur_max)
332 return ret
334 def type_to_str(type_int):
336 t = int(type_int)
337 if t in db_types:
338 return db_types[t]
339 return type_int
341 def type_to_int(type_string):
342 for k in db_types.keys():
343 if db_types[k] == type_string:
344 return k
345 return -1
347 def display_caller_info(printed, cur, param_names):
348 for txt in cur:
349 if not printed:
350 print("file | caller | function | type | parameter | key | value |")
351 printed = 1
353 parameter = int(txt[6])
354 key = txt[7]
355 if len(param_names) and parameter in param_names:
356 key = key.replace("$", param_names[parameter])
358 print("%20s | %20s | %20s |" %(txt[0], txt[1], txt[2]), end = '')
359 print(" %18s |" %(type_to_str(txt[5])), end = '')
360 print(" %2d | %15s | %s" %(parameter, key, txt[8]))
361 return printed
363 def get_caller_info(filename, ptrs, my_type):
364 cur = con.cursor()
365 param_names = get_param_names(filename, func)
366 printed = 0
367 type_filter = ""
368 if my_type != "":
369 type_filter = "and type = %d" %(type_to_int(my_type))
370 for ptr in ptrs:
371 cur.execute("select * from caller_info where function = '%s' %s;" %(ptr, type_filter))
372 printed = display_caller_info(printed, cur, param_names)
374 def print_caller_info(filename, func, my_type = ""):
375 ptrs = get_function_pointers(func)
376 get_caller_info(filename, ptrs, my_type)
378 def merge_values(param_names, vals, cur):
379 for txt in cur:
380 parameter = int(txt[0])
381 name = txt[1]
382 rl = txt_to_rl(txt[2])
383 if parameter in param_names:
384 name = name.replace("$", param_names[parameter])
386 if not parameter in vals:
387 vals[parameter] = {}
389 # the first item on the list is the number of rows. it's incremented
390 # every time we call merge_values().
391 if name in vals[parameter]:
392 vals[parameter][name] = [vals[parameter][name][0] + 1, rl_union(vals[parameter][name][1], rl)]
393 else:
394 vals[parameter][name] = [1, rl]
396 def get_param_names(filename, func):
397 cur = con.cursor()
398 param_names = {}
399 cur.execute("select parameter, value from parameter_name where file = '%s' and function = '%s';" %(filename, func))
400 for txt in cur:
401 parameter = int(txt[0])
402 name = txt[1]
403 param_names[parameter] = name
404 if len(param_names):
405 return param_names
407 cur.execute("select parameter, value from parameter_name where function = '%s';" %(func))
408 for txt in cur:
409 parameter = int(txt[0])
410 name = txt[1]
411 param_names[parameter] = name
412 return param_names
414 def get_caller_count(ptrs):
415 cur = con.cursor()
416 count = 0
417 for ptr in ptrs:
418 cur.execute("select count(distinct(call_id)) from caller_info where function = '%s';" %(ptr))
419 for txt in cur:
420 count += int(txt[0])
421 return count
423 def print_merged_caller_values(filename, func, ptrs, param_names, call_cnt):
424 cur = con.cursor()
425 vals = {}
426 for ptr in ptrs:
427 cur.execute("select parameter, key, value from caller_info where function = '%s' and type = %d;" %(ptr, type_to_int("PARAM_VALUE")))
428 merge_values(param_names, vals, cur);
430 for param in sorted(vals):
431 for name in sorted(vals[param]):
432 if vals[param][name][0] != call_cnt:
433 continue
434 print("%d %s -> %s" %(param, name, rl_to_txt(vals[param][name][1])))
437 def print_unmerged_caller_values(filename, func, ptrs, param_names):
438 cur = con.cursor()
439 for ptr in ptrs:
440 prev = -1
441 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")))
442 for filename, caller, call_id, parameter, name, value in cur:
443 if prev != int(call_id):
444 prev = int(call_id)
446 parameter = int(parameter)
447 if parameter < len(param_names):
448 name = name.replace("$", param_names[parameter])
449 else:
450 name = name.replace("$", "$%d" %(parameter))
452 print("%s | %s | %s | %s" %(filename, caller, name, value))
453 print("==========================")
455 def print_caller_values(filename, func, ptrs):
456 param_names = get_param_names(filename, func)
457 call_cnt = get_caller_count(ptrs)
459 print_merged_caller_values(filename, func, ptrs, param_names, call_cnt)
460 print("==========================")
461 print_unmerged_caller_values(filename, func, ptrs, param_names)
463 def caller_info_values(filename, func):
464 ptrs = get_function_pointers(func)
465 print_caller_values(filename, func, ptrs)
467 def print_return_states(func):
468 cur = con.cursor()
469 cur.execute("select * from return_states where function = '%s';" %(func))
470 count = 0
471 try:
472 for txt in cur:
473 printed = 1
474 if count == 0:
475 print("file | function | return_id | return_value | type | param | key | value |")
476 count += 1
477 print("%s | %s | %2s | %13s" %(txt[0], txt[1], txt[3], txt[4]), end = '')
478 print("| %15s |" %(type_to_str(txt[6])), end = '')
479 print(" %2d | %20s | %20s |" %(txt[7], txt[8], txt[9]))
480 except:
481 print("\n<ERROR parsing: 'select * from return_states where function = '%s';'>\n" %(func))
483 def print_return_implies(func):
484 cur = con.cursor()
485 cur.execute("select * from return_implies where function = '%s';" %(func))
486 count = 0
487 for txt in cur:
488 if not count:
489 print("file | function | type | param | key | value |")
490 count += 1
491 print("%15s | %15s" %(txt[0], txt[1]), end = '')
492 print("| %15s" %(type_to_str(txt[4])), end = '')
493 print("| %3d | %15s | %15s |" %(txt[5], txt[6], txt[7]))
495 def print_type_size(struct_type, member):
496 cur = con.cursor()
497 cur.execute("select * from type_size where type like '(struct %s)->%s';" %(struct_type, member))
498 print("type | size")
499 for txt in cur:
500 print("%-15s | %s" %(txt[0], txt[1]))
502 cur.execute("select * from function_type_size where type like '(struct %s)->%s';" %(struct_type, member))
503 print("file | function | type | size")
504 for txt in cur:
505 print("%-15s | %-15s | %-15s | %s" %(txt[0], txt[1], txt[2], txt[3]))
507 def print_data_info(struct_type, member):
508 cur = con.cursor()
509 cur.execute("select * from data_info where data like '(struct %s)->%s';" %(struct_type, member))
510 print("file | data | type | value")
511 for txt in cur:
512 print("%-15s | %-15s | %-15s | %s" %(txt[0], txt[1], type_to_str(txt[2]), txt[3]))
514 def print_fn_ptrs(func):
515 ptrs = get_function_pointers(func)
516 if not ptrs:
517 return
518 print("%s = " %(func), end = '')
519 print(ptrs)
521 def print_functions(struct, member):
522 cur = con.cursor()
523 if struct:
524 cur.execute("select * from function_ptr where ptr like '(struct %s)->%s';" %(struct, member))
525 elif member.find(" ") >= 0:
526 cur.execute("select * from function_ptr where ptr = '%s';" %(member))
527 else:
528 cur.execute("select * from function_ptr where ptr like '%%->%s';" %(member))
529 print("File | Pointer | Function | Static")
530 for txt in cur:
531 print("%-15s | %-15s | %-15s | %s" %(txt[0], txt[2], txt[1], txt[3]))
533 class CallTree:
534 def __init__(self, func, printed = ""):
535 self.name = func;
536 if printed == "":
537 self.printed = func + "()"
538 else:
539 self.printed = printed;
540 self.callers = []
542 def has_func(self, func):
543 if func == self.name:
544 return True
545 for c in self.callers:
546 if c.has_func(func):
547 return True
548 return False
550 def print_tree(self, out):
551 max_indent = 0
552 for c in self.callers:
553 indent = c.print_tree(out)
554 if indent > max_indent:
555 max_indent = indent
556 if max_indent != 0:
557 out.write("%s-> " %(" " *((max_indent - 1) * 3)))
558 out.write("%s\n" %(self.printed))
559 return max_indent + 1
561 def __repr__(self):
562 out = io.StringIO()
563 indent = 0
564 self.print_tree(out)
565 return out.getvalue()
567 def add_caller(self, func, printed = ""):
568 for c in self.callers:
569 if func == c.name:
570 return None
571 t = CallTree(func, printed)
572 self.callers.append(t)
573 return t
575 def get_callers(func, restrict = ""):
576 if restrict == "":
577 restrict = "and type = 0"
578 ret = []
579 cur = con.cursor()
580 ptrs = get_function_pointers(func)
581 for ptr in ptrs:
582 cur.execute("select distinct caller from caller_info where function = '%s' %s;" %(ptr, restrict))
583 for row in cur:
584 ret.append(row[0])
585 return ret
587 printed_funcs = []
588 def call_tree_helper(func, restrict = "", indent = 0):
589 global printed_funcs
590 if func in printed_funcs:
591 return
592 if func == "too common":
593 return
594 if indent > 30:
595 return
596 printed_funcs.append(func)
597 callers = get_callers(func, restrict)
598 if len(callers) >= 20:
599 print("Over 20 callers for %s()" %(func))
600 return
601 for caller in callers:
602 if caller in printed_funcs:
603 print("%s+ %s()" %(" " * indent, caller))
604 else:
605 print("%s%s()" %(" " * (indent + 2), caller))
606 call_tree_helper(caller, restrict, indent + 2)
608 def print_call_tree(func):
609 global printed_funcs
610 printed_funcs = []
611 print("%s()" %(func))
612 call_tree_helper(func)
614 def get_preempt_callers(call_tree, branch, func):
615 cur = con.cursor()
616 ptrs = get_function_pointers(func)
617 for ptr in ptrs:
618 cur.execute("select caller, value from caller_info where function = '%s' and type = 2054;" %(ptr))
619 for row in cur:
620 func = row[0]
621 if row[1] == "":
622 printed = func + "()"
623 else:
624 printed = func + "() " + row[1]
625 if not call_tree.has_func(func):
626 b = branch.add_caller(func, printed)
627 get_preempt_callers(call_tree, b, func)
628 else:
629 printed = printed + " <duplicate>"
630 branch.add_caller(func, printed)
632 return call_tree
634 def print_preempt_tree(func):
635 global printed_funcs
636 printed_funcs = []
637 call_tree = CallTree(func)
638 get_preempt_callers(call_tree, call_tree, func)
639 print(call_tree)
641 def function_type_value(struct_type, member):
642 cur = con.cursor()
643 cur.execute("select * from function_type_value where type like '(struct %s)->%s';" %(struct_type, member))
644 for txt in cur:
645 print("%-30s | %-30s | %s | %s" %(txt[0], txt[1], txt[2], txt[3]))
647 def rl_too_big(txt):
648 rl = txt_to_rl(txt)
649 ret = ""
650 for idx in range(len(rl)):
651 cur_max = rl[idx][1]
652 if (cur_max > 0xFFFFFFFFFFFFFF):
653 return 1
655 return 0
657 def rl_has_min_untagged(txt):
658 rl = txt_to_rl(txt)
659 ret = ""
660 for idx in range(len(rl)):
661 cur_min = rl[idx][0]
662 if (cur_min == 0xff80000000000000):
663 return 1
665 return 0
667 def rl_is_tagged(txt):
668 if not rl_too_big(txt):
669 return 0
671 if rl_has_min_untagged(txt):
672 return 0
674 return 1
676 def rl_is_treat_untagged(txt):
677 if "[u]" in txt:
678 return 1;
680 return 0
682 def parse_warns_tagged(filename):
683 proc = subprocess.Popen(['cat %s | grep "potentially tagged" | sort | uniq' %(filename)], shell=True, stdout=subprocess.PIPE)
684 while True:
685 line = proc.stdout.readline()
686 if not line:
687 break
689 linepos = re.search("([^\s]+)", line).group(1)
690 groupre = re.search("potentially tagged address \(([^,]+), ([^,]+), ([^\)]+)\)", line)
691 groupre.group(1)
693 func = groupre.group(1)
694 param = int(groupre.group(2))
695 var = groupre.group(3)
697 if ("end" in var or "size" in var or "len" in var):
698 return
700 print("\n%s (func: %s, param: %d:%s) may be caused by:" %(linepos, func, param, var))
702 if (param != -1):
703 if not find_tagged(func, param, 0, []):
704 print(" %s (param %d) (can't walk call tree)" % (func, param))
705 else:
706 print(" %s (variable %s (can't walk call tree)" % (func, var))
708 def find_tagged(func, param, caller_call_id, printed):
710 callers = {}
711 cur = con.cursor()
712 ptrs = get_function_pointers(func)
713 found = 0
715 for ptr in ptrs:
716 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")))
718 for row in cur:
719 if (row[1][0] == '$'):
720 if row[0] not in callers:
721 callers[row[0]] = {}
722 callers[row[0]]["param"] = int(row[1][1])
724 for ptr in ptrs:
725 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")))
727 for row in cur:
728 if not rl_is_tagged(row[2]):
729 continue
730 if rl_is_treat_untagged(row[2]):
731 continue
732 found = 1
733 if row[1] not in callers:
734 callers[row[1]] = {}
735 if "param" not in callers[row[1]]:
736 line = " %s (param ?) -> %s (param %d)" % (row[0], func, param)
737 if line not in printed:
738 printed.append(line)
739 print(line)
740 continue
741 if row[0] not in printed:
742 printed.append(row[0])
743 if not find_tagged(row[0], callers[row[1]]["param"], row[1], printed):
744 print(" %s (param %d)" % (row[0], param))
746 return found
748 def trace_callers(func, param):
749 sources = []
750 prev_type = 0
752 cur = con.cursor()
753 ptrs = get_function_pointers(func)
754 for ptr in ptrs:
755 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))
756 for row in cur:
757 data_type = int(row[0])
758 if data_type == 1014:
759 sources.append((row[1], row[2]))
760 elif data_type == 1028:
761 sources.append(("%", row[2])) # hack...
762 elif data_type == 0 and prev_type == 0:
763 sources.append((row[1], ""))
764 prev_type = data_type
765 return sources
767 def trace_param_helper(func, param, indent = 0):
768 global printed_funcs
769 if func in printed_funcs:
770 return
771 print("%s%s(param %d)" %(" " * indent, func, param))
772 if func == "too common":
773 return
774 if indent > 20:
775 return
776 printed_funcs.append(func)
777 sources = trace_callers(func, param)
778 for path in sources:
780 if len(path[1]) and path[1][0] == '$':
781 p = int(re.findall('\d+', path[1][1:])[0])
782 trace_param_helper(path[0], p, indent + 2)
783 elif len(path[0]) and path[0][0] == '%':
784 print(" %s%s" %(" " * indent, path[1]))
785 else:
786 print("* %s%s %s" %(" " * (indent - 1), path[0], path[1]))
788 def trace_param(func, param):
789 global printed_funcs
790 printed_funcs = []
791 print("tracing %s %d" %(func, param))
792 trace_param_helper(func, param)
794 def print_locals(filename):
795 cur = con.cursor()
796 cur.execute("select file,data,value from data_info where file = '%s' and type = 8029 and value != 0;" %(filename))
797 for txt in cur:
798 print("%s | %s | %s" %(txt[0], txt[1], txt[2]))
800 def constraint(struct_type, member):
801 cur = con.cursor()
802 cur.execute("select * from constraints_required where data like '(struct %s)->%s' or bound like '(struct %s)->%s';" %(struct_type, member, struct_type, member))
803 for txt in cur:
804 print("%-30s | %-30s | %s | %s" %(txt[0], txt[1], txt[2], txt[3]))
806 if len(sys.argv) < 2:
807 usage()
809 if len(sys.argv) == 2:
810 func = sys.argv[1]
811 print_caller_info("", func)
812 elif sys.argv[1] == "info":
813 my_type = ""
814 if len(sys.argv) == 4:
815 my_type = sys.argv[3]
816 func = sys.argv[2]
817 print_caller_info("", func, my_type)
818 elif sys.argv[1] == "call_info":
819 if len(sys.argv) != 4:
820 usage()
821 filename = sys.argv[2]
822 func = sys.argv[3]
823 caller_info_values(filename, func)
824 print_caller_info(filename, func)
825 elif sys.argv[1] == "function_ptr" or sys.argv[1] == "fn_ptr":
826 func = sys.argv[2]
827 print_fn_ptrs(func)
828 elif sys.argv[1] == "return_states":
829 func = sys.argv[2]
830 print_return_states(func)
831 print("================================================")
832 print_return_implies(func)
833 elif sys.argv[1] == "return_implies":
834 func = sys.argv[2]
835 print_return_implies(func)
836 elif sys.argv[1] == "type_size" or sys.argv[1] == "buf_size":
837 struct_type = sys.argv[2]
838 member = sys.argv[3]
839 print_type_size(struct_type, member)
840 elif sys.argv[1] == "data_info":
841 struct_type = sys.argv[2]
842 member = sys.argv[3]
843 print_data_info(struct_type, member)
844 elif sys.argv[1] == "call_tree":
845 func = sys.argv[2]
846 print_call_tree(func)
847 elif sys.argv[1] == "preempt":
848 func = sys.argv[2]
849 print_preempt_tree(func)
850 elif sys.argv[1] == "find_tagged":
851 func = sys.argv[2]
852 param = int(sys.argv[3])
853 find_tagged(func, param, 0, [])
854 elif sys.argv[1] == "parse_warns_tagged":
855 filename = sys.argv[2]
856 parse_warns_tagged(filename)
857 elif sys.argv[1] == "where":
858 if len(sys.argv) == 3:
859 struct_type = "%"
860 member = sys.argv[2]
861 elif len(sys.argv) == 4:
862 struct_type = sys.argv[2]
863 member = sys.argv[3]
864 function_type_value(struct_type, member)
865 elif sys.argv[1] == "local":
866 filename = sys.argv[2]
867 variable = ""
868 if len(sys.argv) == 4:
869 variable = sys.argv[3]
870 local_values(filename, variable)
871 elif sys.argv[1] == "functions":
872 if len(sys.argv) == 4:
873 struct = sys.argv[2]
874 member = sys.argv[3]
875 else:
876 struct = ""
877 member = sys.argv[2]
878 print_functions(struct, member)
879 elif sys.argv[1] == "trace_param":
880 if len(sys.argv) != 4:
881 usage()
882 func = sys.argv[2]
883 param = int(sys.argv[3])
884 trace_param(func, param)
885 elif sys.argv[1] == "locals":
886 if len(sys.argv) != 3:
887 usage()
888 filename = sys.argv[2]
889 print_locals(filename);
890 elif sys.argv[1] == "constraint":
891 if len(sys.argv) == 3:
892 struct_type = "%"
893 member = sys.argv[2]
894 elif len(sys.argv) == 4:
895 struct_type = sys.argv[2]
896 member = sys.argv[3]
897 constraint(struct_type, member)
898 else:
899 usage()