GDB (xrefs)
exsummary.py
Go to the documentation of this file.
1 # Copyright 2011-2015 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 
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)
def print_stack(self, is_indirect)
Definition: exsummary.py:60
def consistency_check(self)
Definition: exsummary.py:45
def function_call(to, frm, location)
Definition: exsummary.py:129
def log(self, message)
Definition: exsummary.py:33
def __init__(self, name)
Definition: exsummary.py:25
def declare_throw(fn_name)
Definition: exsummary.py:113
def declare_cleanup(fn_name)
Definition: exsummary.py:123
def help_and_exit()
Definition: exsummary.py:146
def mark_throw(self, edge, work_list, is_indirect)
Definition: exsummary.py:74
def declare_throw(self)
Definition: exsummary.py:54
def declare_nothrow(fn_name)
Definition: exsummary.py:119
def define_function(fn_name, location)
Definition: exsummary.py:109
def declare_nothrow(self)
Definition: exsummary.py:50
def add_caller(self, caller)
Definition: exsummary.py:40
def set_location(self, location)
Definition: exsummary.py:36
def has_indirect_call(fn_name, location)
Definition: exsummary.py:134
def mark_functions(worklist, is_indirect)
Definition: exsummary.py:141
def declare(fn_name)
Definition: exsummary.py:103
def main()
Definition: exsummary.py:156
def __init__(self, from_fn, to_fn, location)
Definition: exsummary.py:87