From patchwork Mon Dec 24 21:56:51 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tom Tromey X-Patchwork-Id: 30834 Received: (qmail 23154 invoked by alias); 24 Dec 2018 21:57:08 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 23142 invoked by uid 89); 24 Dec 2018 21:57:07 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-26.9 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_PASS autolearn=ham version=3.3.2 spammy=sk:master_, close, reads, keys X-HELO: gateway33.websitewelcome.com Received: from gateway33.websitewelcome.com (HELO gateway33.websitewelcome.com) (192.185.145.9) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Mon, 24 Dec 2018 21:56:58 +0000 Received: from cm11.websitewelcome.com (cm11.websitewelcome.com [100.42.49.5]) by gateway33.websitewelcome.com (Postfix) with ESMTP id DE5882ED341 for ; Mon, 24 Dec 2018 15:56:56 -0600 (CST) Received: from box5379.bluehost.com ([162.241.216.53]) by cmsmtp with SMTP id bYDYgR2OydnCebYDYgZvbx; Mon, 24 Dec 2018 15:56:56 -0600 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=tromey.com; s=default; h=Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:MIME-Version :Content-Type:Content-Transfer-Encoding:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: In-Reply-To:References:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=FdIPbg74KIKbqE73ZF7MHIkeh17NtO3MkLiPC43x/xk=; b=tmGN3PZICn6qf449O55m5X0ggQ fNOvvceTx4eMXqr4Fuc+Hqhyc1KWkfZ48bWkYdM8qX7Klhtl3RJSm4vqD0Y7f+lIGvrETwQYMXKxI TObctQ2KeKjFUJFha1g+l5osA; Received: from 75-166-72-210.hlrn.qwest.net ([75.166.72.210]:38438 helo=bapiya.Home) by box5379.bluehost.com with esmtpsa (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.91) (envelope-from ) id 1gbYDY-0030Su-IH; Mon, 24 Dec 2018 15:56:56 -0600 From: Tom Tromey To: gdb-patches@sourceware.org Cc: Tom Tromey Subject: [PATCH] Remove the exception and cleanup checkers Date: Mon, 24 Dec 2018 14:56:51 -0700 Message-Id: <20181224215651.15706-1-tom@tromey.com> Now that gdb is transitioning away from cleanups, there is no reason to keep the cleanup and exception checker scripts around. This patch removes them. gdb/ChangeLog 2018-12-24 Tom Tromey * contrib/cleanup_check.py: Remove. * contrib/gcc-with-excheck: Remove. * contrib/exsummary.py: Remove. * contrib/excheck.py: Remove. --- gdb/ChangeLog | 7 + gdb/contrib/cleanup_check.py | 335 ----------------------------------- gdb/contrib/excheck.py | 296 ------------------------------- gdb/contrib/exsummary.py | 185 ------------------- gdb/contrib/gcc-with-excheck | 58 ------ 5 files changed, 7 insertions(+), 874 deletions(-) delete mode 100644 gdb/contrib/cleanup_check.py delete mode 100644 gdb/contrib/excheck.py delete mode 100644 gdb/contrib/exsummary.py delete mode 100755 gdb/contrib/gcc-with-excheck diff --git a/gdb/contrib/cleanup_check.py b/gdb/contrib/cleanup_check.py deleted file mode 100644 index 4d0d48872e..0000000000 --- a/gdb/contrib/cleanup_check.py +++ /dev/null @@ -1,335 +0,0 @@ -# Copyright 2013-2018 Free Software Foundation, Inc. -# -# This is free software: you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see -# . - -import gcc -import gccutils -import sys - -want_raii_info = False - -logging = False -show_cfg = False - -def log(msg, indent=0): - global logging - if logging: - sys.stderr.write('%s%s\n' % (' ' * indent, msg)) - sys.stderr.flush() - -def is_cleanup_type(return_type): - if not isinstance(return_type, gcc.PointerType): - return False - if not isinstance(return_type.dereference, gcc.RecordType): - return False - if str(return_type.dereference.name) == 'cleanup': - return True - return False - -def is_constructor(decl): - "Return True if the function DECL is a cleanup constructor; False otherwise" - return is_cleanup_type(decl.type.type) and (not decl.name or str(decl.name) != 'make_final_cleanup') - -destructor_names = set(['do_cleanups', 'discard_cleanups']) - -def is_destructor(decl): - return decl.name in destructor_names - -# This list is just much too long... we should probably have an -# attribute instead. -special_names = set(['do_final_cleanups', 'discard_final_cleanups', - 'save_cleanups', 'save_final_cleanups', - 'restore_cleanups', 'restore_final_cleanups', - 'exceptions_state_mc_init', - 'make_my_cleanup2', 'make_final_cleanup', 'all_cleanups', - 'save_my_cleanups', 'quit_target']) - -def needs_special_treatment(decl): - return decl.name in special_names - -# Sometimes we need a new placeholder object that isn't the same as -# anything else. -class Dummy(object): - def __init__(self, location): - self.location = location - -# A wrapper for a cleanup which has been assigned to a variable. -# This holds the variable and the location. -class Cleanup(object): - def __init__(self, var, location): - self.var = var - self.location = location - -# A class representing a master cleanup. This holds a stack of -# cleanup objects and supports a merging operation. -class MasterCleanup(object): - # Create a new MasterCleanup object. OTHER, if given, is a - # MasterCleanup object to copy. - def __init__(self, other = None): - # 'cleanups' is a list of cleanups. Each element is either a - # Dummy, for an anonymous cleanup, or a Cleanup, for a cleanup - # which was assigned to a variable. - if other is None: - self.cleanups = [] - self.aliases = {} - else: - self.cleanups = other.cleanups[:] - self.aliases = dict(other.aliases) - - def compare_vars(self, definition, argument): - if definition == argument: - return True - if argument in self.aliases: - argument = self.aliases[argument] - if definition in self.aliases: - definition = self.aliases[definition] - return definition == argument - - def note_assignment(self, lhs, rhs): - log('noting assignment %s = %s' % (lhs, rhs), 4) - self.aliases[lhs] = rhs - - # Merge with another MasterCleanup. - # Returns True if this resulted in a change to our state. - def merge(self, other): - # We do explicit iteration like this so we can easily - # update the list after the loop. - counter = -1 - found_named = False - for counter in range(len(self.cleanups) - 1, -1, -1): - var = self.cleanups[counter] - log('merge checking %s' % var, 4) - # Only interested in named cleanups. - if isinstance(var, Dummy): - log('=> merge dummy', 5) - continue - # Now see if VAR is found in OTHER. - if other._find_var(var.var) >= 0: - log ('=> merge found', 5) - break - log('=>merge not found', 5) - found_named = True - if found_named and counter < len(self.cleanups) - 1: - log ('merging to %d' % counter, 4) - if counter < 0: - self.cleanups = [] - else: - self.cleanups = self.cleanups[0:counter] - return True - # If SELF is empty but OTHER has some cleanups, then consider - # that a change as well. - if len(self.cleanups) == 0 and len(other.cleanups) > 0: - log('merging non-empty other', 4) - self.cleanups = other.cleanups[:] - return True - return False - - # Push a new constructor onto our stack. LHS is the - # left-hand-side of the GimpleCall statement. It may be None, - # meaning that this constructor's value wasn't used. - def push(self, location, lhs): - if lhs is None: - obj = Dummy(location) - else: - obj = Cleanup(lhs, location) - log('pushing %s' % lhs, 4) - idx = self._find_var(lhs) - if idx >= 0: - gcc.permerror(location, 'reassigning to known cleanup') - gcc.inform(self.cleanups[idx].location, - 'previous assignment is here') - self.cleanups.append(obj) - - # A helper for merge and pop that finds BACK_TO in self.cleanups, - # and returns the index, or -1 if not found. - def _find_var(self, back_to): - for i in range(len(self.cleanups) - 1, -1, -1): - if isinstance(self.cleanups[i], Dummy): - continue - if self.compare_vars(self.cleanups[i].var, back_to): - return i - return -1 - - # Pop constructors until we find one matching BACK_TO. - # This is invoked when we see a do_cleanups call. - def pop(self, location, back_to): - log('pop:', 4) - i = self._find_var(back_to) - if i >= 0: - self.cleanups = self.cleanups[0:i] - else: - gcc.permerror(location, 'destructor call with unknown argument') - - # Check whether ARG is the current master cleanup. Return True if - # all is well. - def verify(self, location, arg): - log('verify %s' % arg, 4) - return (len(self.cleanups) > 0 - and not isinstance(self.cleanups[0], Dummy) - and self.compare_vars(self.cleanups[0].var, arg)) - - # Check whether SELF is empty. - def isempty(self): - log('isempty: len = %d' % len(self.cleanups), 4) - return len(self.cleanups) == 0 - - # Emit informational warnings about the cleanup stack. - def inform(self): - for item in reversed(self.cleanups): - gcc.inform(item.location, 'leaked cleanup') - -class CleanupChecker: - def __init__(self, fun): - self.fun = fun - self.seen_edges = set() - self.bad_returns = set() - - # This maps BB indices to a list of master cleanups for the - # BB. - self.master_cleanups = {} - - # Pick a reasonable location for the basic block BB. - def guess_bb_location(self, bb): - if isinstance(bb.gimple, list): - for stmt in bb.gimple: - if stmt.loc: - return stmt.loc - return self.fun.end - - # Compute the master cleanup list for BB. - # Modifies MASTER_CLEANUP in place. - def compute_master(self, bb, bb_from, master_cleanup): - if not isinstance(bb.gimple, list): - return - curloc = self.fun.end - for stmt in bb.gimple: - if stmt.loc: - curloc = stmt.loc - if isinstance(stmt, gcc.GimpleCall) and stmt.fndecl: - if is_constructor(stmt.fndecl): - log('saw constructor %s in bb=%d' % (str(stmt.fndecl), bb.index), 2) - self.cleanup_aware = True - master_cleanup.push(curloc, stmt.lhs) - elif is_destructor(stmt.fndecl): - if str(stmt.fndecl.name) != 'do_cleanups': - self.only_do_cleanups_seen = False - log('saw destructor %s in bb=%d, bb_from=%d, argument=%s' - % (str(stmt.fndecl.name), bb.index, bb_from, str(stmt.args[0])), - 2) - master_cleanup.pop(curloc, stmt.args[0]) - elif needs_special_treatment(stmt.fndecl): - pass - # gcc.permerror(curloc, 'function needs special treatment') - elif isinstance(stmt, gcc.GimpleAssign): - if isinstance(stmt.lhs, gcc.VarDecl) and isinstance(stmt.rhs[0], gcc.VarDecl): - master_cleanup.note_assignment(stmt.lhs, stmt.rhs[0]) - elif isinstance(stmt, gcc.GimpleReturn): - if self.is_constructor: - if not master_cleanup.verify(curloc, stmt.retval): - gcc.permerror(curloc, - 'constructor does not return master cleanup') - elif not self.is_special_constructor: - if not master_cleanup.isempty(): - if curloc not in self.bad_returns: - gcc.permerror(curloc, 'cleanup stack is not empty at return') - self.bad_returns.add(curloc) - master_cleanup.inform() - - # Traverse a basic block, updating the master cleanup information - # and propagating to other blocks. - def traverse_bbs(self, edge, bb, bb_from, entry_master): - log('traverse_bbs %d from %d' % (bb.index, bb_from), 1) - - # Propagate the entry MasterCleanup though this block. - master_cleanup = MasterCleanup(entry_master) - self.compute_master(bb, bb_from, master_cleanup) - - modified = False - if bb.index in self.master_cleanups: - # Merge the newly-computed MasterCleanup into the one we - # have already computed. If this resulted in a - # significant change, then we need to re-propagate. - modified = self.master_cleanups[bb.index].merge(master_cleanup) - else: - self.master_cleanups[bb.index] = master_cleanup - modified = True - - # EDGE is None for the entry BB. - if edge is not None: - # If merging cleanups caused a change, check to see if we - # have a bad loop. - if edge in self.seen_edges: - # This error doesn't really help. - # if modified: - # gcc.permerror(self.guess_bb_location(bb), - # 'invalid cleanup use in loop') - return - self.seen_edges.add(edge) - - if not modified: - return - - # Now propagate to successor nodes. - for edge in bb.succs: - self.traverse_bbs(edge, edge.dest, bb.index, master_cleanup) - - def check_cleanups(self): - if not self.fun.cfg or not self.fun.decl: - return 'ignored' - if is_destructor(self.fun.decl): - return 'destructor' - if needs_special_treatment(self.fun.decl): - return 'special' - - self.is_constructor = is_constructor(self.fun.decl) - self.is_special_constructor = not self.is_constructor and str(self.fun.decl.name).find('with_cleanup') > -1 - # Yuck. - if str(self.fun.decl.name) == 'gdb_xml_create_parser_and_cleanup_1': - self.is_special_constructor = True - - if self.is_special_constructor: - gcc.inform(self.fun.start, 'function %s is a special constructor' % (self.fun.decl.name)) - - # If we only see do_cleanups calls, and this function is not - # itself a constructor, then we can convert it easily to RAII. - self.only_do_cleanups_seen = not self.is_constructor - # If we ever call a constructor, then we are "cleanup-aware". - self.cleanup_aware = False - - entry_bb = self.fun.cfg.entry - master_cleanup = MasterCleanup() - self.traverse_bbs(None, entry_bb, -1, master_cleanup) - if want_raii_info and self.only_do_cleanups_seen and self.cleanup_aware: - gcc.inform(self.fun.decl.location, - 'function %s could be converted to RAII' % (self.fun.decl.name)) - if self.is_constructor: - return 'constructor' - return 'OK' - -class CheckerPass(gcc.GimplePass): - def execute(self, fun): - if fun.decl: - log("Starting " + fun.decl.name) - if show_cfg: - dot = gccutils.cfg_to_dot(fun.cfg, fun.decl.name) - gccutils.invoke_dot(dot, name=fun.decl.name) - checker = CleanupChecker(fun) - what = checker.check_cleanups() - if fun.decl: - log(fun.decl.name + ': ' + what, 2) - -ps = CheckerPass(name = 'check-cleanups') -# We need the cfg, but we want a relatively high-level Gimple. -ps.register_after('cfg') diff --git a/gdb/contrib/excheck.py b/gdb/contrib/excheck.py deleted file mode 100644 index 6276ab30ad..0000000000 --- a/gdb/contrib/excheck.py +++ /dev/null @@ -1,296 +0,0 @@ -# Copyright 2011-2018 Free Software Foundation, Inc. -# -# This is free software: you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see -# . - -# This is a GCC plugin that computes some exception-handling data for -# gdb. This data can then be summarized and checked by the -# exsummary.py script. - -# To use: -# * First, install the GCC Python plugin. See -# https://fedorahosted.org/gcc-python-plugin/ -# * export PYTHON_PLUGIN=/full/path/to/plugin/directory -# This should be the directory holding "python.so". -# * cd build/gdb; make mostlyclean -# * make CC=.../gcc-with-excheck -# This will write a number of .py files in the build directory. -# * python .../exsummary.py -# This will show the violations. - -import gcc -import gccutils -import sys - -# Where our output goes. -output_file = None - -# Cleanup functions require special treatment, because they take a -# function argument, but in theory the function must be nothrow. -cleanup_functions = { - 'make_cleanup': 1, - 'make_cleanup_dtor': 1, - 'make_final_cleanup': 1, - 'make_my_cleanup2': 1, - 'make_my_cleanup': 1 -} - -# Functions which may throw but which we want to ignore. -ignore_functions = { - # This one is super special. - 'exceptions_state_mc': 1, - # gdb generally pretends that internal_error cannot throw, even - # though it can. - 'internal_error': 1, - # do_cleanups and friends are supposedly nothrow but we don't want - # to run afoul of the indirect function call logic. - 'do_cleanups': 1, - 'do_final_cleanups': 1 -} - -# Functions which take a function argument, but which are not -# interesting, usually because the argument is not called in the -# current context. -non_passthrough_functions = { - 'signal': 1, - 'add_internal_function': 1 -} - -# Return True if the type is from Python. -def type_is_pythonic(t): - if isinstance(t, gcc.ArrayType): - t = t.type - if not isinstance(t, gcc.RecordType): - return False - # Hack. - return str(t).find('struct Py') == 0 - -# Examine all the fields of a struct. We don't currently need any -# sort of recursion, so this is simple for now. -def examine_struct_fields(initializer): - global output_file - for idx2, value2 in initializer.elements: - if isinstance(idx2, gcc.Declaration): - if isinstance(value2, gcc.AddrExpr): - value2 = value2.operand - if isinstance(value2, gcc.FunctionDecl): - output_file.write("declare_nothrow(%s)\n" - % repr(str(value2.name))) - -# Examine all global variables looking for pointers to functions in -# structures whose types were defined by Python. -def examine_globals(): - global output_file - vars = gcc.get_variables() - for var in vars: - if not isinstance(var.decl, gcc.VarDecl): - continue - output_file.write("################\n") - output_file.write("# Analysis for %s\n" % var.decl.name) - if not var.decl.initial: - continue - if not type_is_pythonic(var.decl.type): - continue - - if isinstance(var.decl.type, gcc.ArrayType): - for idx, value in var.decl.initial.elements: - examine_struct_fields(value) - else: - gccutils.check_isinstance(var.decl.type, gcc.RecordType) - examine_struct_fields(var.decl.initial) - -# Called at the end of compilation to write out some data derived from -# globals and to close the output. -def close_output(*args): - global output_file - examine_globals() - output_file.close() - -# The pass which derives some exception-checking information. We take -# a two-step approach: first we get a call graph from the compiler. -# This is emitted by the plugin as Python code. Then, we run a second -# program that reads all the generated Python and uses it to get a -# global view of exception routes in gdb. -class GdbExceptionChecker(gcc.GimplePass): - def __init__(self, output_file): - gcc.GimplePass.__init__(self, 'gdb_exception_checker') - self.output_file = output_file - - def log(self, obj): - self.output_file.write("# %s\n" % str(obj)) - - # Return true if FN is a call to a method on a Python object. - # We know these cannot throw in the gdb sense. - def fn_is_python_ignorable(self, fn): - if not isinstance(fn, gcc.SsaName): - return False - stmt = fn.def_stmt - if not isinstance(stmt, gcc.GimpleAssign): - return False - if stmt.exprcode is not gcc.ComponentRef: - return False - rhs = stmt.rhs[0] - if not isinstance(rhs, gcc.ComponentRef): - return False - if not isinstance(rhs.field, gcc.FieldDecl): - return False - return rhs.field.name == 'tp_dealloc' or rhs.field.name == 'tp_free' - - # Decode a function call and write something to the output. - # THIS_FUN is the enclosing function that we are processing. - # FNDECL is the call to process; it might not actually be a DECL - # node. - # LOC is the location of the call. - def handle_one_fndecl(self, this_fun, fndecl, loc): - callee_name = '' - if isinstance(fndecl, gcc.AddrExpr): - fndecl = fndecl.operand - if isinstance(fndecl, gcc.FunctionDecl): - # Ordinary call to a named function. - callee_name = str(fndecl.name) - self.output_file.write("function_call(%s, %s, %s)\n" - % (repr(callee_name), - repr(this_fun.decl.name), - repr(str(loc)))) - elif self.fn_is_python_ignorable(fndecl): - # Call to tp_dealloc. - pass - elif (isinstance(fndecl, gcc.SsaName) - and isinstance(fndecl.var, gcc.ParmDecl)): - # We can ignore an indirect call via a parameter to the - # current function, because this is handled via the rule - # for passthrough functions. - pass - else: - # Any other indirect call. - self.output_file.write("has_indirect_call(%s, %s)\n" - % (repr(this_fun.decl.name), - repr(str(loc)))) - return callee_name - - # This does most of the work for examine_one_bb. - # THIS_FUN is the enclosing function. - # BB is the basic block to process. - # Returns True if this block is the header of a TRY_CATCH, False - # otherwise. - def examine_one_bb_inner(self, this_fun, bb): - if not bb.gimple: - return False - try_catch = False - for stmt in bb.gimple: - loc = stmt.loc - if not loc: - loc = this_fun.decl.location - if not isinstance(stmt, gcc.GimpleCall): - continue - callee_name = self.handle_one_fndecl(this_fun, stmt.fn, loc) - - if callee_name == 'exceptions_state_mc_action_iter': - try_catch = True - - global non_passthrough_functions - if callee_name in non_passthrough_functions: - continue - - # We have to specially handle calls where an argument to - # the call is itself a function, e.g., qsort. In general - # we model these as "passthrough" -- we assume that in - # addition to the call the qsort there is also a call to - # the argument function. - for arg in stmt.args: - # We are only interested in arguments which are functions. - t = arg.type - if isinstance(t, gcc.PointerType): - t = t.dereference - if not isinstance(t, gcc.FunctionType): - continue - - if isinstance(arg, gcc.AddrExpr): - arg = arg.operand - - global cleanup_functions - if callee_name in cleanup_functions: - if not isinstance(arg, gcc.FunctionDecl): - gcc.inform(loc, 'cleanup argument not a DECL: %s' % repr(arg)) - else: - # Cleanups must be nothrow. - self.output_file.write("declare_cleanup(%s)\n" - % repr(str(arg.name))) - else: - # Assume we have a passthrough function, like - # qsort or an iterator. We model this by - # pretending there is an ordinary call at this - # point. - self.handle_one_fndecl(this_fun, arg, loc) - return try_catch - - # Examine all the calls in a basic block and generate output for - # them. - # THIS_FUN is the enclosing function. - # BB is the basic block to examine. - # BB_WORKLIST is a list of basic blocks to work on; we add the - # appropriate successor blocks to this. - # SEEN_BBS is a map whose keys are basic blocks we have already - # processed. We use this to ensure that we only visit a given - # block once. - def examine_one_bb(self, this_fun, bb, bb_worklist, seen_bbs): - try_catch = self.examine_one_bb_inner(this_fun, bb) - for edge in bb.succs: - if edge.dest in seen_bbs: - continue - seen_bbs[edge.dest] = 1 - if try_catch: - # This is bogus, but we magically know the right - # answer. - if edge.false_value: - bb_worklist.append(edge.dest) - else: - bb_worklist.append(edge.dest) - - # Iterate over all basic blocks in THIS_FUN. - def iterate_bbs(self, this_fun): - # Iteration must be in control-flow order, because if we see a - # TRY_CATCH construct we need to drop all the contained blocks. - bb_worklist = [this_fun.cfg.entry] - seen_bbs = {} - seen_bbs[this_fun.cfg.entry] = 1 - for bb in bb_worklist: - self.examine_one_bb(this_fun, bb, bb_worklist, seen_bbs) - - def execute(self, fun): - if fun and fun.cfg and fun.decl: - self.output_file.write("################\n") - self.output_file.write("# Analysis for %s\n" % fun.decl.name) - self.output_file.write("define_function(%s, %s)\n" - % (repr(fun.decl.name), - repr(str(fun.decl.location)))) - - global ignore_functions - if fun.decl.name not in ignore_functions: - self.iterate_bbs(fun) - -def main(**kwargs): - global output_file - output_file = open(gcc.get_dump_base_name() + '.gdb_exc.py', 'w') - # We used to use attributes here, but there didn't seem to be a - # big benefit over hard-coding. - output_file.write('declare_throw("throw_exception")\n') - output_file.write('declare_throw("throw_verror")\n') - output_file.write('declare_throw("throw_vfatal")\n') - output_file.write('declare_throw("throw_error")\n') - gcc.register_callback(gcc.PLUGIN_FINISH_UNIT, close_output) - ps = GdbExceptionChecker(output_file) - ps.register_after('ssa') - -main() diff --git a/gdb/contrib/exsummary.py b/gdb/contrib/exsummary.py deleted file mode 100644 index 98ab0d8677..0000000000 --- a/gdb/contrib/exsummary.py +++ /dev/null @@ -1,185 +0,0 @@ -# Copyright 2011-2018 Free Software Foundation, Inc. -# -# This is free software: you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see -# . - -import sys -import glob - -# Compute the summary information from the files created by -# excheck.py. Run in the build directory where you used the -# excheck.py plugin. - -class Function: - def __init__(self, name): - self.name = name - self.location = None - self.callers = [] - self.can_throw = False - self.marked_nothrow = False - self.reason = None - - def log(self, message): - print "%s: note: %s" % (self.location, message) - - def set_location(self, location): - self.location = location - - # CALLER is an Edge. - def add_caller(self, caller): - # self.log("adding call from %s" % caller.from_fn.name) - self.callers.append(caller) - # self.log("len = %d" % len(self.callers)) - - def consistency_check(self): - if self.marked_nothrow and self.can_throw: - print ("%s: error: %s marked as both 'throw' and 'nothrow'" - % (self.location, self.name)) - - def declare_nothrow(self): - self.marked_nothrow = True - self.consistency_check() - - def declare_throw(self): - result = not self.can_throw # Return True the first time - self.can_throw = True - self.consistency_check() - return result - - def print_stack(self, is_indirect): - if is_indirect: - print ("%s: error: function %s is marked nothrow but is assumed to throw due to indirect call" - % (self.location, self.name)) - else: - print ("%s: error: function %s is marked nothrow but can throw" - % (self.location, self.name)) - - edge = self.reason - while edge is not None: - print ("%s: info: via call to %s" - % (edge.location, edge.to_fn.name)) - edge = edge.to_fn.reason - - def mark_throw(self, edge, work_list, is_indirect): - if not self.can_throw: - # self.log("can throw") - self.can_throw = True - self.reason = edge - if self.marked_nothrow: - self.print_stack(is_indirect) - else: - # Do this in the 'else' to avoid extra error - # propagation. - work_list.append(self) - -class Edge: - def __init__(self, from_fn, to_fn, location): - self.from_fn = from_fn - self.to_fn = to_fn - self.location = location - -# Work list of known-throwing functions. -work_list = [] -# Map from function name to Function object. -function_map = {} -# Work list of indirect calls. -indirect_functions = [] -# Whether we should process cleanup functions as well. -process_cleanups = False -# Whether we should process indirect function calls. -process_indirect = False - -def declare(fn_name): - global function_map - if fn_name not in function_map: - function_map[fn_name] = Function(fn_name) - return function_map[fn_name] - -def define_function(fn_name, location): - fn = declare(fn_name) - fn.set_location(location) - -def declare_throw(fn_name): - global work_list - fn = declare(fn_name) - if fn.declare_throw(): - work_list.append(fn) - -def declare_nothrow(fn_name): - fn = declare(fn_name) - fn.declare_nothrow() - -def declare_cleanup(fn_name): - global process_cleanups - fn = declare(fn_name) - if process_cleanups: - fn.declare_nothrow() - -def function_call(to, frm, location): - to_fn = declare(to) - frm_fn = declare(frm) - to_fn.add_caller(Edge(frm_fn, to_fn, location)) - -def has_indirect_call(fn_name, location): - global indirect_functions - fn = declare(fn_name) - phony = Function("") - phony.add_caller(Edge(fn, phony, location)) - indirect_functions.append(phony) - -def mark_functions(worklist, is_indirect): - for callee in worklist: - for edge in callee.callers: - edge.from_fn.mark_throw(edge, worklist, is_indirect) - -def help_and_exit(): - print "Usage: exsummary [OPTION]..." - print "" - print "Read the .py files from the exception checker plugin and" - print "generate an error summary." - print "" - print " --cleanups Include invalid behavior in cleanups" - print " --indirect Include assumed errors due to indirect function calls" - sys.exit(0) - -def main(): - global work_list - global indirect_functions - global process_cleanups - global process_indirect - - for arg in sys.argv: - if arg == '--cleanups': - process_cleanups = True - elif arg == '--indirect': - process_indirect = True - elif arg == '--help': - help_and_exit() - - for fname in sorted(glob.glob('*.c.gdb_exc.py')): - execfile(fname) - print "================" - print "= Ordinary marking" - print "================" - mark_functions(work_list, False) - if process_indirect: - print "================" - print "= Indirect marking" - print "================" - mark_functions(indirect_functions, True) - return 0 - -if __name__ == '__main__': - status = main() - sys.exit(status) diff --git a/gdb/contrib/gcc-with-excheck b/gdb/contrib/gcc-with-excheck deleted file mode 100755 index 0c15e27b64..0000000000 --- a/gdb/contrib/gcc-with-excheck +++ /dev/null @@ -1,58 +0,0 @@ -#!/bin/sh -# Copyright 2011-2018 Free Software Foundation, Inc. -# -# This is free software: you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see -# . - -# You must set PYTHON_PLUGIN in the environment. -# It should be the directory holding the "python.so" file. -# Usage: gcc-with-excheck [-Xx|-Xc] [--] ARGS -# -Xx means to invoke the exception checker. -# -Xc means to invoke the cleanup checker. -# -- means stop processing -X options. -# ARGS are passed to gcc. - -GCC=${GCC:-gcc} -exdir=`dirname $0` - -pargs= -while true; do - case "$1" in - -Xc) - pargs="$pargs -fplugin-arg-python-script=$exdir/cleanup_check.py" - ;; - -Xx) - pargs="$pargs -fplugin-arg-python-script=$exdir/excheck.py" - ;; - -X*) - echo "unrecognized argument $1" 1>&2 - exit 1 - ;; - --) - shift - break - ;; - *) - break - ;; - esac - shift -done - -# Recent versions of the Python plugin build two .so files in -# different directories, so we have to set this. This will be fixed -# upstream at some point. -export LD_LIBRARY_PATH=$PYTHON_PLUGIN:$PYTHON_PLUGIN/gcc-c-api - -gcc -fplugin=$PYTHON_PLUGIN/python.so $pargs "$@"