1 # Copyright 2011-2015 Free Software Foundation, Inc.
3 # This is free software: you can redistribute it and/or modify it
4 # under the terms of the GNU General Public License as published by
5 # the Free Software Foundation, either version 3 of the License, or
6 # (at your option) any later version.
8 # This program is distributed in the hope that it will be useful, but
9 # WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 # General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program. If not, see
15 # <http://www.gnu.org/licenses/>.
20 # Compute the summary information from the files created by
21 # excheck.py. Run in the build directory where you used the
25 def __init__(self
, name
):
29 self
.can_throw
= False
30 self
.marked_nothrow
= False
33 def log(self
, message
):
34 print "%s: note: %s" % (self
.location
, message
)
36 def set_location(self
, location
):
37 self
.location
= location
40 def add_caller(self
, caller
):
41 # self.log("adding call from %s" % caller.from_fn.name)
42 self
.callers
.append(caller
)
43 # self.log("len = %d" % len(self.callers))
45 def consistency_check(self
):
46 if self
.marked_nothrow
and self
.can_throw
:
47 print ("%s: error: %s marked as both 'throw' and 'nothrow'"
48 % (self
.location
, self
.name
))
50 def declare_nothrow(self
):
51 self
.marked_nothrow
= True
52 self
.consistency_check()
54 def declare_throw(self
):
55 result
= not self
.can_throw
# Return True the first time
57 self
.consistency_check()
60 def print_stack(self
, is_indirect
):
62 print ("%s: error: function %s is marked nothrow but is assumed to throw due to indirect call"
63 % (self
.location
, self
.name
))
65 print ("%s: error: function %s is marked nothrow but can throw"
66 % (self
.location
, self
.name
))
69 while edge
is not None:
70 print ("%s: info: via call to %s"
71 % (edge
.location
, edge
.to_fn
.name
))
72 edge
= edge
.to_fn
.reason
74 def mark_throw(self
, edge
, work_list
, is_indirect
):
75 if not self
.can_throw
:
76 # self.log("can throw")
79 if self
.marked_nothrow
:
80 self
.print_stack(is_indirect
)
82 # Do this in the 'else' to avoid extra error
84 work_list
.append(self
)
87 def __init__(self
, from_fn
, to_fn
, location
):
88 self
.from_fn
= from_fn
90 self
.location
= location
92 # Work list of known-throwing functions.
94 # Map from function name to Function object.
96 # Work list of indirect calls.
97 indirect_functions
= []
98 # Whether we should process cleanup functions as well.
99 process_cleanups
= False
100 # Whether we should process indirect function calls.
101 process_indirect
= False
103 def declare(fn_name
):
105 if fn_name
not in function_map
:
106 function_map
[fn_name
] = Function(fn_name
)
107 return function_map
[fn_name
]
109 def define_function(fn_name
, location
):
110 fn
= declare(fn_name
)
111 fn
.set_location(location
)
113 def declare_throw(fn_name
):
115 fn
= declare(fn_name
)
116 if fn
.declare_throw():
119 def declare_nothrow(fn_name
):
120 fn
= declare(fn_name
)
123 def declare_cleanup(fn_name
):
124 global process_cleanups
125 fn
= declare(fn_name
)
129 def function_call(to
, frm
, location
):
131 frm_fn
= declare(frm
)
132 to_fn
.add_caller(Edge(frm_fn
, to_fn
, location
))
134 def has_indirect_call(fn_name
, location
):
135 global indirect_functions
136 fn
= declare(fn_name
)
137 phony
= Function("<indirect call>")
138 phony
.add_caller(Edge(fn
, phony
, location
))
139 indirect_functions
.append(phony
)
141 def mark_functions(worklist
, is_indirect
):
142 for callee
in worklist
:
143 for edge
in callee
.callers
:
144 edge
.from_fn
.mark_throw(edge
, worklist
, is_indirect
)
147 print "Usage: exsummary [OPTION]..."
149 print "Read the .py files from the exception checker plugin and"
150 print "generate an error summary."
152 print " --cleanups Include invalid behavior in cleanups"
153 print " --indirect Include assumed errors due to indirect function calls"
158 global indirect_functions
159 global process_cleanups
160 global process_indirect
163 if arg
== '--cleanups':
164 process_cleanups
= True
165 elif arg
== '--indirect':
166 process_indirect
= True
167 elif arg
== '--help':
170 for fname
in sorted(glob
.glob('*.c.gdb_exc.py')):
172 print "================"
173 print "= Ordinary marking"
174 print "================"
175 mark_functions(work_list
, False)
177 print "================"
178 print "= Indirect marking"
179 print "================"
180 mark_functions(indirect_functions
, True)
183 if __name__
== '__main__':