3 # Copyright (C) 2013 Oracle.
5 # Licensed under the Open Software License version 1.1
14 con
= sqlite3
.connect('smatch_db.sqlite')
15 except sqlite3
.Error
as e
:
16 print("Error %s:" % e
.args
[0])
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.")
37 def get_function_pointers_helper(func
):
39 cur
.execute("select distinct ptr from function_ptr where function = '%s';" %(func))
42 if ptr
in function_ptrs
:
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
):
52 function_ptrs
= [func
]
53 searched_ptrs
= [func
]
54 get_function_pointers_helper(func
)
57 db_types
= { 0: "INTERNAL",
68 1009: "LOCK_RELEASED",
69 1010: "ABSOLUTE_LIMITS",
80 1023: "UNTRACKED_PARAM",
85 1028: "COMPARE_LIMIT",
86 1029: "PARAM_COMPARE",
90 1033: "CONSTRAINT_REQUIRED",
107 9017: "USER_DATA_SET",
109 9019: "USER_PTR_SET",
111 8019: "NO_OVERFLOW_SIMPLE",
116 9023: "LOCK_RESTORED",
117 9024: "KNOWN_LOCKED",
118 9025: "KNOWN_UNLOCKED",
121 9027: "REFCOUNT_INC",
122 9028: "REFCOUNT_DEC",
125 def add_range(rl
, min_val
, max_val
):
132 return [[min_val
, max_val
]]
134 for idx
in range(len(rl
)):
138 # we already merged the new range but we might need to change later
139 # ranges if they over lap with more than one
141 # join with added range
142 if max_val
+ 1 == cur_min
:
143 ret
[len(ret
) - 1][1] = cur_max
147 if max_val
< cur_min
:
148 ret
.append([cur_min
, cur_max
])
152 if max_val
< cur_max
:
153 ret
[len(ret
) - 1][1] = cur_max
159 # join 2 ranges into one
160 if max_val
+ 1 == cur_min
:
161 ret
.append([min_val
, cur_max
])
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
])
170 # range is partially below
171 if min_val
< cur_min
:
172 if max_val
<= cur_max
:
173 ret
.append([min_val
, cur_max
])
177 ret
.append([min_val
, max_val
])
180 # range already included
181 if max_val
<= cur_max
:
182 ret
.append([cur_min
, cur_max
])
185 # range partially above
186 if min_val
<= cur_max
:
187 ret
.append([cur_min
, max_val
])
190 # join 2 ranges on the other side
191 if min_val
- 1 == cur_max
:
192 ret
.append([cur_min
, max_val
])
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
202 elif not check_next
: # it's past the end of the rl
203 ret
.append([min_val
, max_val
])
207 def rl_union(rl1
, rl2
):
210 ret
= add_range(ret
, r
[0], r
[1])
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
))
222 elif txt
== "s32min":
224 elif txt
== "s16min":
226 elif txt
== "s64max":
228 elif txt
== "s32max":
230 elif txt
== "s16max":
232 elif txt
== "u64max":
234 elif txt
== "ptr_max":
236 elif txt
== "u32max":
238 elif txt
== "u16max":
249 elif val
== -(2**31):
251 elif val
== -(2**15):
253 elif val
== 2**63 - 1:
255 elif val
== 2**31 - 1:
257 elif val
== 2**15 - 1:
259 elif val
== 2**64 - 1:
261 elif val
== 2**32 - 1:
263 elif val
== 2**16 - 1:
270 def get_next_str(txt
):
282 elif txt
[0] == 's' or txt
[0] == 'u':
288 for char
in txt
[parsed
:]:
289 if char
== '-' or char
== '[':
300 pairs
= txt
.split(",")
302 cnt
, min_str
= get_next_str(pair
)
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))
319 for idx
in range(len(rl
)):
326 if cur_min
== cur_max
:
327 ret
+= val_to_txt(cur_min
)
329 ret
+= val_to_txt(cur_min
)
331 ret
+= val_to_txt(cur_max
)
334 def type_to_str(type_int
):
341 def type_to_int(type_string
):
342 for k
in db_types
.keys():
343 if db_types
[k
] == type_string
:
347 def display_caller_info(printed
, cur
, param_names
):
350 print("file | caller | function | type | parameter | key | value |")
353 parameter
= int(txt
[6])
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]))
363 def get_caller_info(filename
, ptrs
, my_type
):
365 param_names
= get_param_names(filename
, func
)
369 type_filter
= "and type = %d" %(type_to_int(my_type
))
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
):
380 parameter
= int(txt
[0])
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
:
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
)]
394 vals
[parameter
][name
] = [1, rl
]
396 def get_param_names(filename
, func
):
399 cur
.execute("select parameter, value from parameter_name where file = '%s' and function = '%s';" %(filename
, func
))
401 parameter
= int(txt
[0])
403 param_names
[parameter
] = name
407 cur
.execute("select parameter, value from parameter_name where function = '%s';" %(func))
409 parameter
= int(txt
[0])
411 param_names
[parameter
] = name
414 def get_caller_count(ptrs
):
418 cur
.execute("select count(distinct(call_id)) from caller_info where function = '%s';" %(ptr))
423 def print_merged_caller_values(filename
, func
, ptrs
, param_names
, call_cnt
):
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
:
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
):
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
):
446 parameter
= int(parameter
)
447 if parameter
< len(param_names
):
448 name
= name
.replace("$", param_names
[parameter
])
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
):
469 cur
.execute("select * from return_states where function = '%s';" %(func))
475 print("file | function | return_id | return_value | type | param | key | value |")
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]))
481 print("\n<ERROR parsing: 'select * from return_states where function = '%s';'>\n" %(func))
483 def print_return_implies(func
):
485 cur
.execute("select * from return_implies where function = '%s';" %(func))
489 print("file | function | type | param | key | value |")
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
):
497 cur
.execute("select * from type_size where type like '(struct %s)->%s';" %(struct_type
, member
))
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")
505 print("%-15s | %-15s | %-15s | %s" %(txt
[0], txt
[1], txt
[2], txt
[3]))
507 def print_data_info(struct_type
, member
):
509 cur
.execute("select * from data_info where data like '(struct %s)->%s';" %(struct_type
, member
))
510 print("file | data | type | value")
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
)
518 print("%s = " %(func), end
= '')
521 def print_functions(struct
, member
):
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))
528 cur
.execute("select * from function_ptr where ptr like '%%->%s';" %(member))
529 print("File | Pointer | Function | Static")
531 print("%-15s | %-15s | %-15s | %s" %(txt
[0], txt
[2], txt
[1], txt
[3]))
534 def __init__(self
, func
, printed
= ""):
537 self
.printed
= func
+ "()"
539 self
.printed
= printed
;
542 def has_func(self
, func
):
543 if func
== self
.name
:
545 for c
in self
.callers
:
550 def print_tree(self
, out
):
552 for c
in self
.callers
:
553 indent
= c
.print_tree(out
)
554 if indent
> max_indent
:
557 out
.write("%s-> " %(" " *((max_indent
- 1) * 3)))
558 out
.write("%s\n" %(self
.printed
))
559 return max_indent
+ 1
565 return out
.getvalue()
567 def add_caller(self
, func
, printed
= ""):
568 for c
in self
.callers
:
571 t
= CallTree(func
, printed
)
572 self
.callers
.append(t
)
575 def get_callers(func
, restrict
= ""):
577 restrict
= "and type = 0"
580 ptrs
= get_function_pointers(func
)
582 cur
.execute("select distinct caller from caller_info where function = '%s' %s;" %(ptr
, restrict
))
588 def call_tree_helper(func
, restrict
= "", indent
= 0):
590 if func
in printed_funcs
:
592 if func
== "too common":
596 printed_funcs
.append(func
)
597 callers
= get_callers(func
, restrict
)
598 if len(callers
) >= 20:
599 print("Over 20 callers for %s()" %(func))
601 for caller
in callers
:
602 if caller
in printed_funcs
:
603 print("%s+ %s()" %(" " * indent
, caller
))
605 print("%s%s()" %(" " * (indent
+ 2), caller
))
606 call_tree_helper(caller
, restrict
, indent
+ 2)
608 def print_call_tree(func
):
611 print("%s()" %(func))
612 call_tree_helper(func
)
614 def get_preempt_callers(call_tree
, branch
, func
):
616 ptrs
= get_function_pointers(func
)
618 cur
.execute("select caller, value from caller_info where function = '%s' and type = 2054;" %(ptr))
622 printed
= func
+ "()"
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
)
629 printed
= printed
+ " <duplicate>"
630 branch
.add_caller(func
, printed
)
634 def print_preempt_tree(func
):
637 call_tree
= CallTree(func
)
638 get_preempt_callers(call_tree
, call_tree
, func
)
641 def function_type_value(struct_type
, member
):
643 cur
.execute("select * from function_type_value where type like '(struct %s)->%s';" %(struct_type
, member
))
645 print("%-30s | %-30s | %s | %s" %(txt
[0], txt
[1], txt
[2], txt
[3]))
650 for idx
in range(len(rl
)):
652 if (cur_max
> 0xFFFFFFFFFFFFFF):
657 def rl_has_min_untagged(txt
):
660 for idx
in range(len(rl
)):
662 if (cur_min
== 0xff80000000000000):
667 def rl_is_tagged(txt
):
668 if not rl_too_big(txt
):
671 if rl_has_min_untagged(txt
):
676 def rl_is_treat_untagged(txt
):
682 def parse_warns_tagged(filename
):
683 proc
= subprocess
.Popen(['cat %s | grep "potentially tagged" | sort | uniq' %(filename)], shell
=True, stdout
=subprocess
.PIPE
)
685 line
= proc
.stdout
.readline()
689 linepos
= re
.search("([^\s]+)", line
).group(1)
690 groupre
= re
.search("potentially tagged address \(([^,]+), ([^,]+), ([^\)]+)\)", line
)
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
):
700 print("\n%s (func: %s, param: %d:%s) may be caused by:" %(linepos
, func
, param
, var
))
703 if not find_tagged(func
, param
, 0, []):
704 print(" %s (param %d) (can't walk call tree)" % (func
, param
))
706 print(" %s (variable %s (can't walk call tree)" % (func
, var
))
708 def find_tagged(func
, param
, caller_call_id
, printed
):
712 ptrs
= get_function_pointers(func
)
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")))
719 if (row
[1][0] == '$'):
720 if row
[0] not in callers
:
722 callers
[row
[0]]["param"] = int(row
[1][1])
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")))
728 if not rl_is_tagged(row
[2]):
730 if rl_is_treat_untagged(row
[2]):
733 if row
[1] not in callers
:
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
:
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
))
748 def trace_callers(func
, param
):
753 ptrs
= get_function_pointers(func
)
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
))
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
767 def trace_param_helper(func
, param
, indent
= 0):
769 if func
in printed_funcs
:
771 print("%s%s(param %d)" %(" " * indent
, func
, param
))
772 if func
== "too common":
776 printed_funcs
.append(func
)
777 sources
= trace_callers(func
, param
)
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]))
786 print("* %s%s %s" %(" " * (indent
- 1), path
[0], path
[1]))
788 def trace_param(func
, param
):
791 print("tracing %s %d" %(func
, param
))
792 trace_param_helper(func
, param
)
794 def print_locals(filename
):
796 cur
.execute("select file,data,value from data_info where file = '%s' and type = 8029 and value != 0;" %(filename))
798 print("%s | %s | %s" %(txt
[0], txt
[1], txt
[2]))
800 def constraint(struct_type
, member
):
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
))
804 print("%-30s | %-30s | %s | %s" %(txt
[0], txt
[1], txt
[2], txt
[3]))
806 if len(sys
.argv
) < 2:
809 if len(sys
.argv
) == 2:
811 print_caller_info("", func
)
812 elif sys
.argv
[1] == "info":
814 if len(sys
.argv
) == 4:
815 my_type
= sys
.argv
[3]
817 print_caller_info("", func
, my_type
)
818 elif sys
.argv
[1] == "call_info":
819 if len(sys
.argv
) != 4:
821 filename
= sys
.argv
[2]
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":
828 elif sys
.argv
[1] == "return_states":
830 print_return_states(func
)
831 print("================================================")
832 print_return_implies(func
)
833 elif sys
.argv
[1] == "return_implies":
835 print_return_implies(func
)
836 elif sys
.argv
[1] == "type_size" or sys
.argv
[1] == "buf_size":
837 struct_type
= sys
.argv
[2]
839 print_type_size(struct_type
, member
)
840 elif sys
.argv
[1] == "data_info":
841 struct_type
= sys
.argv
[2]
843 print_data_info(struct_type
, member
)
844 elif sys
.argv
[1] == "call_tree":
846 print_call_tree(func
)
847 elif sys
.argv
[1] == "preempt":
849 print_preempt_tree(func
)
850 elif sys
.argv
[1] == "find_tagged":
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:
861 elif len(sys
.argv
) == 4:
862 struct_type
= sys
.argv
[2]
864 function_type_value(struct_type
, member
)
865 elif sys
.argv
[1] == "local":
866 filename
= sys
.argv
[2]
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:
878 print_functions(struct
, member
)
879 elif sys
.argv
[1] == "trace_param":
880 if len(sys
.argv
) != 4:
883 param
= int(sys
.argv
[3])
884 trace_param(func
, param
)
885 elif sys
.argv
[1] == "locals":
886 if len(sys
.argv
) != 3:
888 filename
= sys
.argv
[2]
889 print_locals(filename
);
890 elif sys
.argv
[1] == "constraint":
891 if len(sys
.argv
) == 3:
894 elif len(sys
.argv
) == 4:
895 struct_type
= sys
.argv
[2]
897 constraint(struct_type
, member
)