GDB (xrefs)

exsummary.py
Go to the documentation of this file.
1 # Copyright 2011-2018 Free Software Foundation, Inc.
2 #
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.
7 #
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.
12 #
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/>.
16
17 import sys
18 import glob
19
20 # Compute the summary information from the files created by
21 # excheck.py. Run in the build directory where you used the
22 # excheck.py plugin.
23
24 class Function:
25 def __init__(self, name):
26 self.name = name
27 self.location = None
28 self.callers = []
29 self.can_throw = False
30 self.marked_nothrow = False
31 self.reason = None
32
33 def log(self, message):
34 print "%s: note: %s" % (self.location, message)
35
36 def set_location(self, location):
37 self.location = location
38
39 # CALLER is an Edge.
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))
44
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))
49
50 def declare_nothrow(self):
51 self.marked_nothrow = True
52 self.consistency_check()
53
54 def declare_throw(self):
55 result = not self.can_throw # Return True the first time
56 self.can_throw = True
57 self.consistency_check()
58 return result
59
60 def print_stack(self, is_indirect):
61 if 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))
64 else:
65 print ("%s: error: function %s is marked nothrow but can throw"
66 % (self.location, self.name))
67
68 edge = self.reason
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
73
74 def mark_throw(self, edge, work_list, is_indirect):
75 if not self.can_throw:
76 # self.log("can throw")
77 self.can_throw = True
78 self.reason = edge
79 if self.marked_nothrow:
80 self.print_stack(is_indirect)
81 else:
82 # Do this in the 'else' to avoid extra error
83 # propagation.
84 work_list.append(self)
85
86 class Edge:
87 def __init__(self, from_fn, to_fn, location):
88 self.from_fn = from_fn
89 self.to_fn = to_fn
90 self.location = location
91
92 # Work list of known-throwing functions.
93 work_list = []
94 # Map from function name to Function object.
95 function_map = {}
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
102
103 def declare(fn_name):
104 global function_map
105 if fn_name not in function_map:
106 function_map[fn_name] = Function(fn_name)
107 return function_map[fn_name]
108
109 def define_function(fn_name, location):
110 fn = declare(fn_name)
111 fn.set_location(location)
112
113 def declare_throw(fn_name):
114 global work_list
115 fn = declare(fn_name)
116 if fn.declare_throw():
117 work_list.append(fn)
118
119 def declare_nothrow(fn_name):
120 fn = declare(fn_name)
121 fn.declare_nothrow()
122
123 def declare_cleanup(fn_name):
124 global process_cleanups
125 fn = declare(fn_name)
126 if process_cleanups:
127 fn.declare_nothrow()
128
129 def function_call(to, frm, location):
130 to_fn = declare(to)
131 frm_fn = declare(frm)
132 to_fn.add_caller(Edge(frm_fn, to_fn, location))
133
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)
140
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)
145
146 def help_and_exit():
147 print "Usage: exsummary [OPTION]..."
148 print ""
149 print "Read the .py files from the exception checker plugin and"
150 print "generate an error summary."
151 print ""
152 print " --cleanups Include invalid behavior in cleanups"
153 print " --indirect Include assumed errors due to indirect function calls"
154 sys.exit(0)
155
156 def main():
157 global work_list
158 global indirect_functions
159 global process_cleanups
160 global process_indirect
161
162 for arg in sys.argv:
163 if arg == '--cleanups':
164 process_cleanups = True
165 elif arg == '--indirect':
166 process_indirect = True
167 elif arg == '--help':
168 help_and_exit()
169
170 for fname in sorted(glob.glob('*.c.gdb_exc.py')):
171 execfile(fname)
172 print "================"
173 print "= Ordinary marking"
174 print "================"
175 mark_functions(work_list, False)
176 if process_indirect:
177 print "================"
178 print "= Indirect marking"
179 print "================"
180 mark_functions(indirect_functions, True)
181 return 0
182
183 if __name__ == '__main__':
184 status = main()
185 sys.exit(status)
exsummary.Function.print_stack
def print_stack(self, is_indirect)
Definition: exsummary.py:60
exsummary.Edge
Definition: exsummary.py:86
exsummary.Function.consistency_check
def consistency_check(self)
Definition: exsummary.py:45
exsummary.function_call
def function_call(to, frm, location)
Definition: exsummary.py:129
exsummary.Function.log
def log(self, message)
Definition: exsummary.py:33
exsummary.Function.__init__
def __init__(self, name)
Definition: exsummary.py:25
exsummary.Function.location
location
Definition: exsummary.py:27
exsummary.declare_throw
def declare_throw(fn_name)
Definition: exsummary.py:113
exsummary.declare_cleanup
def declare_cleanup(fn_name)
Definition: exsummary.py:123
exsummary.Function.can_throw
can_throw
Definition: exsummary.py:29
exsummary.Edge.from_fn
from_fn
Definition: exsummary.py:88
exsummary.help_and_exit
def help_and_exit()
Definition: exsummary.py:146
exsummary.Function.name
name
Definition: exsummary.py:26
exsummary.Function.mark_throw
def mark_throw(self, edge, work_list, is_indirect)
Definition: exsummary.py:74
exsummary.Function.declare_throw
def declare_throw(self)
Definition: exsummary.py:54
exsummary.declare_nothrow
def declare_nothrow(fn_name)
Definition: exsummary.py:119
exsummary.Function.reason
reason
Definition: exsummary.py:31
exsummary.define_function
def define_function(fn_name, location)
Definition: exsummary.py:109
exsummary.Function.declare_nothrow
def declare_nothrow(self)
Definition: exsummary.py:50
exsummary.Function.add_caller
def add_caller(self, caller)
Definition: exsummary.py:40
exsummary.Function.set_location
def set_location(self, location)
Definition: exsummary.py:36
exsummary.Edge.to_fn
to_fn
Definition: exsummary.py:89
exsummary.has_indirect_call
def has_indirect_call(fn_name, location)
Definition: exsummary.py:134
exsummary.mark_functions
def mark_functions(worklist, is_indirect)
Definition: exsummary.py:141
exsummary.declare
def declare(fn_name)
Definition: exsummary.py:103
exsummary.Function.callers
callers
Definition: exsummary.py:28
exsummary.Function.marked_nothrow
marked_nothrow
Definition: exsummary.py:30
exsummary.Function
Definition: exsummary.py:24
exsummary.main
def main()
Definition: exsummary.py:156
exsummary.Edge.location
location
Definition: exsummary.py:90
exsummary.Edge.__init__
def __init__(self, from_fn, to_fn, location)
Definition: exsummary.py:87