GDB (API)
/home/stan/gdb/src/gdb/contrib/exsummary.py
Go to the documentation of this file.
00001 #   Copyright 2011, 2013 Free Software Foundation, Inc.
00002 #
00003 #   This is free software: you can redistribute it and/or modify it
00004 #   under the terms of the GNU General Public License as published by
00005 #   the Free Software Foundation, either version 3 of the License, or
00006 #   (at your option) any later version.
00007 #
00008 #   This program is distributed in the hope that it will be useful, but
00009 #   WITHOUT ANY WARRANTY; without even the implied warranty of
00010 #   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00011 #   General Public License for more details.
00012 #
00013 #   You should have received a copy of the GNU General Public License
00014 #   along with this program.  If not, see
00015 #   <http://www.gnu.org/licenses/>.
00016 
00017 import sys
00018 import glob
00019 
00020 # Compute the summary information from the files created by
00021 # excheck.py.  Run in the build directory where you used the
00022 # excheck.py plugin.
00023 
00024 class Function:
00025     def __init__(self, name):
00026         self.name = name
00027         self.location = None
00028         self.callers = []
00029         self.can_throw = False
00030         self.marked_nothrow = False
00031         self.reason = None
00032 
00033     def log(self, message):
00034         print "%s: note: %s" % (self.location, message)
00035 
00036     def set_location(self, location):
00037         self.location = location
00038 
00039     # CALLER is an Edge.
00040     def add_caller(self, caller):
00041         # self.log("adding call from %s" % caller.from_fn.name)
00042         self.callers.append(caller)
00043         # self.log("len = %d" % len(self.callers))
00044 
00045     def consistency_check(self):
00046         if self.marked_nothrow and self.can_throw:
00047             print ("%s: error: %s marked as both 'throw' and 'nothrow'"
00048                    % (self.location, self.name))
00049 
00050     def declare_nothrow(self):
00051         self.marked_nothrow = True
00052         self.consistency_check()
00053 
00054     def declare_throw(self):
00055         result = not self.can_throw # Return True the first time
00056         self.can_throw = True
00057         self.consistency_check()
00058         return result
00059 
00060     def print_stack(self, is_indirect):
00061         if is_indirect:
00062             print ("%s: error: function %s is marked nothrow but is assumed to throw due to indirect call"
00063                    % (self.location, self.name))
00064         else:
00065             print ("%s: error: function %s is marked nothrow but can throw"
00066                    % (self.location, self.name))
00067 
00068         edge = self.reason
00069         while edge is not None:
00070             print ("%s: info: via call to %s"
00071                    % (edge.location, edge.to_fn.name))
00072             edge = edge.to_fn.reason
00073 
00074     def mark_throw(self, edge, work_list, is_indirect):
00075         if not self.can_throw:
00076             # self.log("can throw")
00077             self.can_throw = True
00078             self.reason = edge
00079             if self.marked_nothrow:
00080                 self.print_stack(is_indirect)
00081             else:
00082                 # Do this in the 'else' to avoid extra error
00083                 # propagation.
00084                 work_list.append(self)
00085 
00086 class Edge:
00087     def __init__(self, from_fn, to_fn, location):
00088         self.from_fn = from_fn
00089         self.to_fn = to_fn
00090         self.location = location
00091 
00092 # Work list of known-throwing functions.
00093 work_list = []
00094 # Map from function name to Function object.
00095 function_map = {}
00096 # Work list of indirect calls.
00097 indirect_functions = []
00098 # Whether we should process cleanup functions as well.
00099 process_cleanups = False
00100 # Whether we should process indirect function calls.
00101 process_indirect = False
00102 
00103 def declare(fn_name):
00104     global function_map
00105     if fn_name not in function_map:
00106         function_map[fn_name] = Function(fn_name)
00107     return function_map[fn_name]
00108 
00109 def define_function(fn_name, location):
00110     fn = declare(fn_name)
00111     fn.set_location(location)
00112 
00113 def declare_throw(fn_name):
00114     global work_list
00115     fn = declare(fn_name)
00116     if fn.declare_throw():
00117         work_list.append(fn)
00118 
00119 def declare_nothrow(fn_name):
00120     fn = declare(fn_name)
00121     fn.declare_nothrow()
00122 
00123 def declare_cleanup(fn_name):
00124     global process_cleanups
00125     fn = declare(fn_name)
00126     if process_cleanups:
00127         fn.declare_nothrow()
00128 
00129 def function_call(to, frm, location):
00130     to_fn = declare(to)
00131     frm_fn = declare(frm)
00132     to_fn.add_caller(Edge(frm_fn, to_fn, location))
00133 
00134 def has_indirect_call(fn_name, location):
00135     global indirect_functions
00136     fn = declare(fn_name)
00137     phony = Function("<indirect call>")
00138     phony.add_caller(Edge(fn, phony, location))
00139     indirect_functions.append(phony)
00140 
00141 def mark_functions(worklist, is_indirect):
00142     for callee in worklist:
00143         for edge in callee.callers:
00144             edge.from_fn.mark_throw(edge, worklist, is_indirect)
00145 
00146 def help_and_exit():
00147     print "Usage: exsummary [OPTION]..."
00148     print ""
00149     print "Read the .py files from the exception checker plugin and"
00150     print "generate an error summary."
00151     print ""
00152     print "  --cleanups     Include invalid behavior in cleanups"
00153     print "  --indirect     Include assumed errors due to indirect function calls"
00154     sys.exit(0)
00155 
00156 def main():
00157     global work_list
00158     global indirect_functions
00159     global process_cleanups
00160     global process_indirect
00161 
00162     for arg in sys.argv:
00163         if arg == '--cleanups':
00164             process_cleanups = True
00165         elif arg == '--indirect':
00166             process_indirect = True
00167         elif arg == '--help':
00168             help_and_exit()
00169 
00170     for fname in sorted(glob.glob('*.c.gdb_exc.py')):
00171         execfile(fname)
00172     print "================"
00173     print "= Ordinary marking"
00174     print "================"
00175     mark_functions(work_list, False)
00176     if process_indirect:
00177         print "================"
00178         print "= Indirect marking"
00179         print "================"
00180         mark_functions(indirect_functions, True)
00181     return 0
00182 
00183 if __name__ == '__main__':
00184     status = main()
00185     sys.exit(status)
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines