From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 18604 invoked by alias); 8 Oct 2014 18:51:13 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 18592 invoked by uid 89); 8 Oct 2014 18:51:12 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-0.4 required=5.0 tests=AWL,BAYES_50,FREEMAIL_FROM,RCVD_IN_DNSWL_LOW,SPF_PASS autolearn=ham version=3.3.2 X-HELO: mail-pd0-f174.google.com Received: from mail-pd0-f174.google.com (HELO mail-pd0-f174.google.com) (209.85.192.174) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-SHA encrypted) ESMTPS; Wed, 08 Oct 2014 18:51:08 +0000 Received: by mail-pd0-f174.google.com with SMTP id y13so7335489pdi.33 for ; Wed, 08 Oct 2014 11:51:06 -0700 (PDT) X-Received: by 10.70.8.195 with SMTP id t3mr13330966pda.62.1412794266517; Wed, 08 Oct 2014 11:51:06 -0700 (PDT) Received: from msticlxl57.ims.intel.com (fmdmzpr02-ext.fm.intel.com. [192.55.55.37]) by mx.google.com with ESMTPSA id of9sm707552pbc.6.2014.10.08.11.51.04 for (version=TLSv1 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 08 Oct 2014 11:51:05 -0700 (PDT) Date: Wed, 08 Oct 2014 18:51:00 -0000 From: Ilya Enkovich To: gcc-patches@gcc.gnu.org Cc: Jeff Law Subject: [PATCH, Pointer Bounds Checker 14/x] Passes [1/n] Expand interfaces Message-ID: <20141008185054.GA13454@msticlxl57.ims.intel.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.5.21 (2010-09-15) X-IsSubscribed: yes X-SW-Source: 2014-10/txt/msg00688.txt.bz2 Hi, This patch starts a series which is a result of split of Pointer Bounds Checker patch #14 (Pointer Bounds Checker passes). This patch introduces compiler flags used by checker and helper functions mostly used by expand pass. Thanks, Ilya -- 2014-10-08 Ilya Enkovich * tree-chkp.c: New. * tree-chkp.h: New. * rtl-chkp.c: New. * rtl-chkp.h: New. * Makefile.in (OBJS): Add rtl-chkp.o and tree-chkp.o. (GTFILES): Add tree-chkp.c. * c-family/c.opt (fchkp-check-incomplete-type): New. (fchkp-zero-input-bounds-for-main): New. (fchkp-first-field-has-own-bounds): New. (fchkp-narrow-bounds): New. (fchkp-narrow-to-innermost-array): New. (fchkp-optimize): New. (fchkp-use-fast-string-functions): New. (fchkp-use-nochk-string-functions): New. (fchkp-use-static-bounds): New. (fchkp-use-static-const-bounds): New. (fchkp-treat-zero-dynamic-size-as-infinite): New. (fchkp-check-read): New. (fchkp-check-write): New. (fchkp-store-bounds): New. (fchkp-instrument-calls): New. (fchkp-instrument-marked-only): New. * cppbuiltin.c (define_builtin_macros_for_compilation_flags): Add __CHKP__ macro when Pointer Bounds Checker is on. diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 97b439a..3113a9f 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1328,6 +1328,7 @@ OBJS = \ reload1.o \ reorg.o \ resource.o \ + rtl-chkp.o \ rtl-error.o \ rtl.o \ rtlhash.o \ @@ -1386,6 +1387,7 @@ OBJS = \ tree-outof-ssa.o \ tree-parloops.o \ tree-phinodes.o \ + tree-chkp.o \ tree-predcom.o \ tree-pretty-print.o \ tree-profile.o \ @@ -2254,6 +2256,7 @@ GTFILES = $(CPP_ID_DATA_H) $(srcdir)/input.h $(srcdir)/coretypes.h \ $(srcdir)/stringpool.c $(srcdir)/tree.c $(srcdir)/varasm.c \ $(srcdir)/gimple.h \ $(srcdir)/gimple-ssa.h \ + $(srcdir)/tree-chkp.c \ $(srcdir)/tree-ssanames.c $(srcdir)/tree-eh.c $(srcdir)/tree-ssa-address.c \ $(srcdir)/tree-cfg.c \ $(srcdir)/tree-dfa.c \ diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt index 3c5ebc0..1ca5a95 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -955,6 +955,79 @@ Common Report Var(flag_check_pointer_bounds) Add Pointer Bounds Checker instrumentation. fchkp-* flags are used to control instrumentation. Currently available for C, C++ and ObjC. +fchkp-check-incomplete-type +C ObjC C++ ObjC++ Report Var(flag_chkp_incomplete_type) Init(1) +Generate pointer bounds checks for variables with incomplete type + +fchkp-zero-input-bounds-for-main +C ObjC C++ ObjC++ Report Var(flag_chkp_zero_input_bounds_for_main) Init(0) +Use zero bounds for all incoming arguments in 'main' function. It helps when +instrumented binaries are used with legacy libs. + +fchkp-first-field-has-own-bounds +C ObjC C++ ObjC++ RejectNegative Report Var(flag_chkp_first_field_has_own_bounds) +Forces Pointer Bounds Checker to use narrowed bounds for address of the first +field in the structure. By default pointer to the first field has the same +bounds as pointer to the whole structure. + +fchkp-narrow-bounds +C ObjC C++ ObjC++ Report Var(flag_chkp_narrow_bounds) Init(1) +Control how Pointer Bounds Checker handle pointers to object fields. When +narrowing is on, field bounds are used. Otherwise full object bounds are used. + +fchkp-narrow-to-innermost-array +C ObjC C++ ObjC++ RejectNegative Report Var(flag_chkp_narrow_to_innermost_arrray) +Forces Pointer Bounds Checker to use bounds of the innermost arrays in case of +nested static arryas access. By default outermost array is used. + +fchkp-optimize +C ObjC C++ ObjC++ LTO Report Var(flag_chkp_optimize) Init(-1) +Allow Pointer Bounds Checker optimizations. By default allowed +on optimization levels >0. + +fchkp-use-fast-string-functions +C ObjC C++ ObjC++ LTO Report Var(flag_chkp_use_fast_string_functions) Init(0) +Allow to use *_nobnd versions of string functions by Pointer Bounds Checker. + +fchkp-use-nochk-string-functions +C ObjC C++ ObjC++ LTO Report Var(flag_chkp_use_nochk_string_functions) Init(0) +Allow to use *_nochk versions of string functions by Pointer Bounds Checker. + +fchkp-use-static-bounds +C ObjC C++ ObjC++ Report Var(flag_chkp_use_static_bounds) Init(1) +Use statically initialized variable for vars bounds instead of +generating them each time it is required. + +fchkp-use-static-const-bounds +C ObjC C++ ObjC++ Report Var(flag_chkp_use_static_const_bounds) Init(-1) +Use statically initialized variable for constant bounds instead of +generating them each time it is required. + +fchkp-treat-zero-dynamic-size-as-infinite +C ObjC C++ ObjC++ Report Var(flag_chkp_zero_dynamic_size_as_infinite) Init(0) +With this option zero size obtained dynamically for objects with +incomplete type will be treated as infinite. + +fchkp-check-read +C ObjC C++ ObjC++ LTO Report Var(flag_chkp_check_read) Init(1) +Generate checks for all read accesses to memory. + +fchkp-check-write +C ObjC C++ ObjC++ LTO Report Var(flag_chkp_check_write) Init(1) +Generate checks for all write accesses to memory. + +fchkp-store-bounds +C ObjC C++ ObjC++ LTO Report Var(flag_chkp_store_bounds) Init(1) +Generate bounds stores for pointer writes. + +fchkp-instrument-calls +C ObjC C++ ObjC++ LTO Report Var(flag_chkp_instrument_calls) Init(1) +Generate bounds passing for calls. + +fchkp-instrument-marked-only +C ObjC C++ ObjC++ LTO Report Var(flag_chkp_instrument_marked_only) Init(0) +Instrument only functions marked with bnd_instrument attribute. + fcilkplus C ObjC C++ ObjC++ LTO Report Var(flag_cilkplus) Init(0) Enable Cilk Plus diff --git a/gcc/cppbuiltin.c b/gcc/cppbuiltin.c index fbcd9b0..3fc2f8a 100644 --- a/gcc/cppbuiltin.c +++ b/gcc/cppbuiltin.c @@ -107,6 +107,9 @@ define_builtin_macros_for_compilation_flags (cpp_reader *pfile) flag_finite_math_only); if (flag_cilkplus) cpp_define (pfile, "__cilk=200"); + + if (flag_check_pointer_bounds) + cpp_define (pfile, "__CHKP__"); } diff --git a/gcc/rtl-chkp.c b/gcc/rtl-chkp.c new file mode 100644 index 0000000..4c68119 --- /dev/null +++ b/gcc/rtl-chkp.c @@ -0,0 +1,299 @@ +/* RTL manipulation functions exported by Pointer Bounds Checker. + Copyright (C) 2014 Free Software Foundation, Inc. + Contributed by Ilya Enkovich (ilya.enkovich@intel.com) + +This file is part of GCC. + +GCC 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, or (at your option) any later +version. + +GCC 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 GCC; see the file COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "rtl-chkp.h" +#include "tree-chkp.h" +#include "expr.h" +#include "target.h" +#include "tree-ssa-alias.h" +#include "internal-fn.h" +#include "is-a.h" +#include "predict.h" +#include "basic-block.h" +#include "gimple-expr.h" +#include "gimple.h" +#include "bitmap.h" + +struct hash_map *chkp_rtx_bounds_map; + +/* Get bounds rtx associated with NODE via + chkp_set_rtl_bounds call. */ +rtx +chkp_get_rtl_bounds (tree node) +{ + rtx *slot; + + if (!chkp_rtx_bounds_map) + return NULL_RTX; + + slot = chkp_rtx_bounds_map->get (node); + return slot ? *slot : NULL_RTX; +} + +/* Associate bounds rtx VAL with NODE. */ +void +chkp_set_rtl_bounds (tree node, rtx val) +{ + if (!chkp_rtx_bounds_map) + chkp_rtx_bounds_map = new hash_map; + + chkp_rtx_bounds_map->put (node, val); +} + +/* Reset all bounds stored via chkp_set_rtl_bounds. */ +void +chkp_reset_rtl_bounds () +{ + if (!chkp_rtx_bounds_map) + return; + + delete chkp_rtx_bounds_map; + chkp_rtx_bounds_map = NULL; +} + +/* Split SLOT identifying slot for function value or + argument into two parts SLOT_VAL and SLOT_BND. + First is the slot for regular value and the other one is + for bounds. */ +void +chkp_split_slot (rtx slot, rtx *slot_val, rtx *slot_bnd) +{ + int i; + int val_num = 0; + int bnd_num = 0; + rtx *val_tmps; + rtx *bnd_tmps; + + *slot_bnd = 0; + + if (!slot + || GET_CODE (slot) != PARALLEL) + { + *slot_val = slot; + return; + } + + val_tmps = XALLOCAVEC (rtx, XVECLEN (slot, 0)); + bnd_tmps = XALLOCAVEC (rtx, XVECLEN (slot, 0)); + + for (i = 0; i < XVECLEN (slot, 0); i++) + { + rtx elem = XVECEXP (slot, 0, i); + rtx reg = GET_CODE (elem) == EXPR_LIST ? XEXP (elem, 0) : elem; + + if (!reg) + continue; + + if (POINTER_BOUNDS_MODE_P (GET_MODE (reg)) || CONST_INT_P (reg)) + bnd_tmps[bnd_num++] = elem; + else + val_tmps[val_num++] = elem; + } + + gcc_assert (val_num); + + if (!bnd_num) + { + *slot_val = slot; + return; + } + + if ((GET_CODE (val_tmps[0]) == EXPR_LIST) || (val_num > 1)) + *slot_val = gen_rtx_PARALLEL (GET_MODE (slot), + gen_rtvec_v (val_num, val_tmps)); + else + *slot_val = val_tmps[0]; + + if ((GET_CODE (bnd_tmps[0]) == EXPR_LIST) || (bnd_num > 1)) + *slot_bnd = gen_rtx_PARALLEL (VOIDmode, + gen_rtvec_v (bnd_num, bnd_tmps)); + else + *slot_bnd = bnd_tmps[0]; +} + +/* Join previously splitted to VAL and BND rtx for function + value or argument and return it. */ +rtx +chkp_join_splitted_slot (rtx val, rtx bnd) +{ + rtx res; + int i, n = 0; + + if (!bnd) + return val; + + if (GET_CODE (val) == PARALLEL) + n += XVECLEN (val, 0); + else + n++; + + if (GET_CODE (bnd) == PARALLEL) + n += XVECLEN (bnd, 0); + else + n++; + + res = gen_rtx_PARALLEL (GET_MODE (val), rtvec_alloc (n)); + + n = 0; + + if (GET_CODE (val) == PARALLEL) + for (i = 0; i < XVECLEN (val, 0); i++) + XVECEXP (res, 0, n++) = XVECEXP (val, 0, i); + else + XVECEXP (res, 0, n++) = val; + + if (GET_CODE (bnd) == PARALLEL) + for (i = 0; i < XVECLEN (bnd, 0); i++) + XVECEXP (res, 0, n++) = XVECEXP (bnd, 0, i); + else + XVECEXP (res, 0, n++) = bnd; + + return res; +} + +/* If PAR is PARALLEL holding registers then transform + it into PARALLEL holding EXPR_LISTs of those regs + and zero constant (similar to how function value + on multiple registers looks like). */ +void +chkp_put_regs_to_expr_list (rtx par) +{ + int n; + + if (GET_CODE (par) != PARALLEL + || GET_CODE (XVECEXP (par, 0, 0)) == EXPR_LIST) + return; + + for (n = 0; n < XVECLEN (par, 0); n++) + XVECEXP (par, 0, n) = gen_rtx_EXPR_LIST (VOIDmode, + XVECEXP (par, 0, n), + const0_rtx); +} + +/* Search rtx PAR describing function return value for an + item related to value at offset OFFS and return it. + Return NULL if item was not found. */ +rtx +chkp_get_value_with_offs (rtx par, rtx offs) +{ + int n; + + gcc_assert (GET_CODE (par) == PARALLEL); + + for (n = 0; n < XVECLEN (par, 0); n++) + { + rtx par_offs = XEXP (XVECEXP (par, 0, n), 1); + if (INTVAL (offs) == INTVAL (par_offs)) + return XEXP (XVECEXP (par, 0, n), 0); + } + + return NULL; +} + +/* Emit instructions to store BOUNDS for pointer VALUE + stored in MEM. + Function is used by expand to pass bounds for args + passed on stack. */ +void +chkp_emit_bounds_store (rtx bounds, rtx value, rtx mem) +{ + gcc_assert (MEM_P (mem)); + + if (REG_P (bounds) || CONST_INT_P (bounds)) + { + rtx ptr; + + if (REG_P (value)) + ptr = value; + else + { + rtx slot = adjust_address (value, Pmode, 0); + ptr = gen_reg_rtx (Pmode); + emit_move_insn (ptr, slot); + } + + if (CONST_INT_P (bounds)) + bounds = targetm.calls.load_bounds_for_arg (value, ptr, bounds); + + targetm.calls.store_bounds_for_arg (ptr, mem, + bounds, NULL); + } + else + { + int i; + + gcc_assert (GET_CODE (bounds) == PARALLEL); + gcc_assert (GET_CODE (value) == PARALLEL || MEM_P (value) || REG_P (value)); + + for (i = 0; i < XVECLEN (bounds, 0); i++) + { + rtx reg = XEXP (XVECEXP (bounds, 0, i), 0); + rtx offs = XEXP (XVECEXP (bounds, 0, i), 1); + rtx slot = adjust_address (mem, Pmode, INTVAL (offs)); + rtx ptr; + + if (GET_CODE (value) == PARALLEL) + ptr = chkp_get_value_with_offs (value, offs); + else if (MEM_P (value)) + { + rtx tmp = adjust_address (value, Pmode, INTVAL (offs)); + ptr = gen_reg_rtx (Pmode); + emit_move_insn (ptr, tmp); + } + else + ptr = gen_rtx_SUBREG (Pmode, value, INTVAL (offs)); + + targetm.calls.store_bounds_for_arg (ptr, slot, reg, NULL); + } + } +} + +/* Emit code to copy bounds for structure VALUE of type TYPE + copied to SLOT. */ +void +chkp_copy_bounds_for_stack_parm (rtx slot, rtx value, tree type) +{ + bitmap have_bound = chkp_find_bound_slots (type); + bitmap_iterator bi; + unsigned i; + rtx tmp = NULL, bnd; + + gcc_assert (TYPE_SIZE (type)); + gcc_assert (MEM_P (value)); + gcc_assert (MEM_P (slot)); + gcc_assert (RECORD_OR_UNION_TYPE_P (type)); + + EXECUTE_IF_SET_IN_BITMAP (have_bound, 0, i, bi) + { + rtx ptr = adjust_address (value, Pmode, i * POINTER_SIZE / 8); + rtx to = adjust_address (slot, Pmode, i * POINTER_SIZE / 8); + + if (!tmp) + tmp = gen_reg_rtx (Pmode); + + emit_move_insn (tmp, ptr); + bnd = targetm.calls.load_bounds_for_arg (ptr, tmp, NULL); + targetm.calls.store_bounds_for_arg (tmp, to, bnd, NULL); + } + + BITMAP_FREE (have_bound); +} diff --git a/gcc/rtl-chkp.h b/gcc/rtl-chkp.h new file mode 100644 index 0000000..543cc83 --- /dev/null +++ b/gcc/rtl-chkp.h @@ -0,0 +1,40 @@ +/* Declaration of interface functions of Pointer Bounds Checker. + Copyright (C) 2014 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC 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, or (at your option) any later +version. + +GCC 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 GCC; see the file COPYING3. If not see +. */ + +#ifndef GCC_RTL_CHKP_H +#define GCC_RTL_CHKP_H + +#include "coretypes.h" + +#define DECL_BOUNDS_RTL(NODE) (chkp_get_rtl_bounds (DECL_WRTL_CHECK (NODE))) + +#define SET_DECL_BOUNDS_RTL(NODE, VAL) \ + (chkp_set_rtl_bounds (DECL_WRTL_CHECK (NODE), VAL)) + +extern rtx chkp_get_rtl_bounds (tree node); +extern void chkp_set_rtl_bounds (tree node, rtx val); +extern void chkp_reset_rtl_bounds (); +extern void chkp_split_slot (rtx slot, rtx *slot_val, rtx *slot_bnd); +extern rtx chkp_join_splitted_slot (rtx val, rtx bnd); +extern rtx chkp_get_value_with_offs (rtx par, rtx offs); +extern void chkp_copy_bounds_for_stack_parm (rtx slot, rtx value, tree type); +extern void chkp_emit_bounds_store (rtx bounds, rtx value, rtx mem); +extern void chkp_put_regs_to_expr_list (rtx par); + +#endif /* GCC_RTL_CHKP_H */ diff --git a/gcc/tree-chkp.c b/gcc/tree-chkp.c new file mode 100644 index 0000000..4ab8de6 --- /dev/null +++ b/gcc/tree-chkp.c @@ -0,0 +1,528 @@ +/* Pointer Bounds Checker insrumentation pass. + Copyright (C) 2014 Free Software Foundation, Inc. + Contributed by Ilya Enkovich (ilya.enkovich@intel.com) + +This file is part of GCC. + +GCC 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, or (at your option) any later +version. + +GCC 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 GCC; see the file COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tree-core.h" +#include "stor-layout.h" +#include "varasm.h" +#include "tree.h" +#include "target.h" +#include "tree-iterator.h" +#include "tree-cfg.h" +#include "langhooks.h" +#include "tree-pass.h" +#include "hashtab.h" +#include "diagnostic.h" +#include "ggc.h" +#include "output.h" +#include "internal-fn.h" +#include "is-a.h" +#include "predict.h" +#include "cfgloop.h" +#include "stringpool.h" +#include "tree-ssa-alias.h" +#include "tree-ssanames.h" +#include "tree-ssa-operands.h" +#include "tree-ssa-address.h" +#include "tree-ssa.h" +#include "ipa-inline.h" +#include "basic-block.h" +#include "tree-ssa-loop-niter.h" +#include "gimple-expr.h" +#include "gimple.h" +#include "tree-phinodes.h" +#include "gimple-ssa.h" +#include "ssa-iterators.h" +#include "gimple-pretty-print.h" +#include "gimple-iterator.h" +#include "gimplify.h" +#include "gimplify-me.h" +#include "print-tree.h" +#include "expr.h" +#include "tree-ssa-propagate.h" +#include "gimple-fold.h" +#include "tree-chkp.h" +#include "gimple-walk.h" +#include "rtl.h" /* For MEM_P, assign_temp. */ +#include "tree-dfa.h" + +#define chkp_bndldx_fndecl \ + (targetm.builtin_chkp_function (BUILT_IN_CHKP_BNDLDX)) +#define chkp_bndstx_fndecl \ + (targetm.builtin_chkp_function (BUILT_IN_CHKP_BNDSTX)) +#define chkp_checkl_fndecl \ + (targetm.builtin_chkp_function (BUILT_IN_CHKP_BNDCL)) +#define chkp_checku_fndecl \ + (targetm.builtin_chkp_function (BUILT_IN_CHKP_BNDCU)) +#define chkp_bndmk_fndecl \ + (targetm.builtin_chkp_function (BUILT_IN_CHKP_BNDMK)) +#define chkp_ret_bnd_fndecl \ + (targetm.builtin_chkp_function (BUILT_IN_CHKP_BNDRET)) +#define chkp_intersect_fndecl \ + (targetm.builtin_chkp_function (BUILT_IN_CHKP_INTERSECT)) +#define chkp_narrow_bounds_fndecl \ + (targetm.builtin_chkp_function (BUILT_IN_CHKP_NARROW)) +#define chkp_sizeof_fndecl \ + (targetm.builtin_chkp_function (BUILT_IN_CHKP_SIZEOF)) +#define chkp_extract_lower_fndecl \ + (targetm.builtin_chkp_function (BUILT_IN_CHKP_EXTRACT_LOWER)) +#define chkp_extract_upper_fndecl \ + (targetm.builtin_chkp_function (BUILT_IN_CHKP_EXTRACT_UPPER)) + +static GTY (()) tree chkp_zero_bounds_var; + +struct hash_map *chkp_bounds_map; + +#define CHKP_ZERO_BOUNDS_VAR_NAME "__chkp_zero_bounds" + +/* Return 1 if function FNDECL is instrumented by Pointer + Bounds Checker. */ +bool +chkp_function_instrumented_p (tree fndecl) +{ + return fndecl + && lookup_attribute ("chkp instrumented", DECL_ATTRIBUTES (fndecl)); +} + +/* Mark function FNDECL as instrumented. */ +void +chkp_function_mark_instrumented (tree fndecl) +{ + if (chkp_function_instrumented_p (fndecl)) + return; + + DECL_ATTRIBUTES (fndecl) + = tree_cons (get_identifier ("chkp instrumented"), NULL, + DECL_ATTRIBUTES (fndecl)); +} + +/* Return true when STMT is builtin call to instrumentation function + corresponding to CODE. */ + +bool +chkp_gimple_call_builtin_p (gimple call, + enum built_in_function code) +{ + tree fndecl; + if (is_gimple_call (call) + && (fndecl = targetm.builtin_chkp_function (code)) + && gimple_call_fndecl (call) == fndecl) + return true; + return false; +} + +/* Emit code to store zero bounds for PTR located at MEM. */ +void +chkp_expand_bounds_reset_for_mem (tree mem, tree ptr) +{ + tree zero_bnd, bnd, addr, bndstx; + + if (flag_chkp_use_static_const_bounds) + zero_bnd = chkp_get_zero_bounds_var (); + else + zero_bnd = chkp_build_make_bounds_call (integer_zero_node, + integer_zero_node); + bnd = make_tree (pointer_bounds_type_node, + assign_temp (pointer_bounds_type_node, 0, 1)); + addr = build1 (ADDR_EXPR, + build_pointer_type (TREE_TYPE (mem)), mem); + bndstx = chkp_build_bndstx_call (addr, ptr, bnd); + + expand_assignment (bnd, zero_bnd, false); + expand_normal (bndstx); +} + +/* Mark statement S to not be instrumented. */ +static void +chkp_mark_stmt (gimple s) +{ + gimple_set_plf (s, GF_PLF_1, true); +} + +/* Mark statement S to be instrumented. */ +static void +chkp_unmark_stmt (gimple s) +{ + gimple_set_plf (s, GF_PLF_1, false); +} + +/* Return 1 if statement S should not be instrumented. */ +static bool +chkp_marked_stmt_p (gimple s) +{ + return gimple_plf (s, GF_PLF_1); +} + +/* Build and return bndmk call which creates bounds for structure + pointed by PTR. Structure should have complete type. */ +tree +chkp_make_bounds_for_struct_addr (tree ptr) +{ + tree type = TREE_TYPE (ptr); + tree size; + + gcc_assert (POINTER_TYPE_P (type)); + + size = TYPE_SIZE (TREE_TYPE (type)); + + gcc_assert (size); + + return build_call_nary (pointer_bounds_type_node, + build_fold_addr_expr (chkp_bndmk_fndecl), + 2, ptr, size); +} + +/* Return 1 if type TYPE is a pointer type or a + structure having a pointer type as one of its fields. + Otherwise return 0. */ +bool +chkp_type_has_pointer (const_tree type) +{ + bool res = false; + + if (BOUNDED_TYPE_P (type)) + res = true; + else if (RECORD_OR_UNION_TYPE_P (type)) + { + tree field; + + for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) + if (TREE_CODE (field) == FIELD_DECL) + res = res || chkp_type_has_pointer (TREE_TYPE (field)); + } + else if (TREE_CODE (type) == ARRAY_TYPE) + res = chkp_type_has_pointer (TREE_TYPE (type)); + + return res; +} + +unsigned +chkp_type_bounds_count (const_tree type) +{ + unsigned res = 0; + + if (!type) + res = 0; + else if (BOUNDED_TYPE_P (type)) + res = 1; + else if (RECORD_OR_UNION_TYPE_P (type)) + { + bitmap have_bound = chkp_find_bound_slots (type); + res = bitmap_count_bits (have_bound); + BITMAP_FREE (have_bound); + } + + return res; +} + +/* Get bounds associated with NODE via + chkp_set_bounds call. */ +tree +chkp_get_bounds (tree node) +{ + tree *slot; + + if (!chkp_bounds_map) + return NULL_TREE; + + slot = chkp_bounds_map->get (node); + return slot ? *slot : NULL_TREE; +} + +/* Associate bounds VAL with NODE. */ +void +chkp_set_bounds (tree node, tree val) +{ + if (!chkp_bounds_map) + chkp_bounds_map = new hash_map; + + chkp_bounds_map->put (node, val); +} + +/* Force OP to be suitable for using as an argument for call. + New statements (if any) go to SEQ. */ +static tree +chkp_force_gimple_call_op (tree op, gimple_seq *seq) +{ + gimple_seq stmts; + gimple_stmt_iterator si; + + op = force_gimple_operand (unshare_expr (op), &stmts, true, NULL_TREE); + + for (si = gsi_start (stmts); !gsi_end_p (si); gsi_next (&si)) + chkp_mark_stmt (gsi_stmt (si)); + + gimple_seq_add_seq (seq, stmts); + + return op; +} + +/* Fill HAVE_BOUND output bitmap with information about + bounds requred for object of type TYPE. + + OFFS is used for recursive calls and holds basic + offset of TYPE in outer structure in bits. + + HAVE_BOUND[i] is set to 1 if there is a field + in TYPE which has pointer type and offset + equal to i * POINTER_SIZE - OFFS in bits. */ +void +chkp_find_bound_slots_1 (const_tree type, bitmap have_bound, + HOST_WIDE_INT offs) +{ + if (BOUNDED_TYPE_P (type)) + bitmap_set_bit (have_bound, offs / POINTER_SIZE); + else if (RECORD_OR_UNION_TYPE_P (type)) + { + tree field; + + for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) + if (TREE_CODE (field) == FIELD_DECL) + { + HOST_WIDE_INT field_offs + = TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (field)); + if (DECL_FIELD_OFFSET (field)) + field_offs += TREE_INT_CST_LOW (DECL_FIELD_OFFSET (field)) * 8; + chkp_find_bound_slots_1 (TREE_TYPE (field), have_bound, + offs + field_offs); + } + } + else if (TREE_CODE (type) == ARRAY_TYPE) + { + tree maxval = TYPE_MAX_VALUE (TYPE_DOMAIN (type)); + tree etype = TREE_TYPE (type); + HOST_WIDE_INT esize = TREE_INT_CST_LOW (TYPE_SIZE (etype)); + unsigned HOST_WIDE_INT cur; + + if (!maxval || integer_minus_onep (maxval)) + return; + + for (cur = 0; cur <= TREE_INT_CST_LOW (maxval); cur++) + chkp_find_bound_slots_1 (etype, have_bound, offs + cur * esize); + } +} + +/* Return bitmap holding information about bounds for + type TYPE. See chkp_find_bound_slots_1 for more + details. + + Caller is responsible for deallocation of returned + bitmap. */ +bitmap +chkp_find_bound_slots (const_tree type) +{ + bitmap res = BITMAP_ALLOC (NULL); + chkp_find_bound_slots_1 (type, res, 0); + return res; +} + +/* Return constant static bounds var with specified LB and UB + if such var exists in varpool. Return NULL otherwise. */ +static tree +chkp_find_const_bounds_var (HOST_WIDE_INT lb, + HOST_WIDE_INT ub) +{ + tree val = targetm.chkp_make_bounds_constant (lb, ub); + struct varpool_node *node; + + /* We expect bounds constant is represented as a complex value + of two pointer sized integers. */ + gcc_assert (TREE_CODE (val) == COMPLEX_CST); + + FOR_EACH_VARIABLE (node) + if (POINTER_BOUNDS_P (node->decl) + && TREE_READONLY (node->decl) + && DECL_INITIAL (node->decl) + && TREE_CODE (DECL_INITIAL (node->decl)) == COMPLEX_CST + && tree_int_cst_equal (TREE_REALPART (DECL_INITIAL (node->decl)), + TREE_REALPART (val)) + && tree_int_cst_equal (TREE_IMAGPART (DECL_INITIAL (node->decl)), + TREE_IMAGPART (val))) + return node->decl; + + return NULL; +} + +/* Return constant static bounds var with specified bounds LB and UB. + If such var does not exists then new var is created with specified NAME. */ +static tree +chkp_make_static_const_bounds (HOST_WIDE_INT lb, + HOST_WIDE_INT ub, + const char *name) +{ + tree var; + + /* With LTO we may have constant bounds already in varpool. + Try to find it. */ + var = chkp_find_const_bounds_var (lb, ub); + + if (var) + return var; + + var = build_decl (UNKNOWN_LOCATION, VAR_DECL, + get_identifier (name), pointer_bounds_type_node); + + TREE_PUBLIC (var) = 1; + TREE_USED (var) = 1; + TREE_READONLY (var) = 1; + TREE_STATIC (var) = 1; + TREE_ADDRESSABLE (var) = 0; + DECL_ARTIFICIAL (var) = 1; + DECL_COMDAT (var) = 1; + DECL_READ_P (var) = 1; + DECL_INITIAL (var) = targetm.chkp_make_bounds_constant (lb, ub); + /* We may use this symbol during ctors generation in chkp_finish_file + when all symbols are emitted. Force output to avoid undefined + symbols in ctors. */ + varpool_node::get_create (var)->set_comdat_group (DECL_ASSEMBLER_NAME (var)); + varpool_node::get_create (var)->force_output = 1; + varpool_node::finalize_decl (var); + + return var; +} + +/* Return var holding zero bounds. */ +tree +chkp_get_zero_bounds_var (void) +{ + if (!chkp_zero_bounds_var) + chkp_zero_bounds_var + = chkp_make_static_const_bounds (0, -1, + CHKP_ZERO_BOUNDS_VAR_NAME); + return chkp_zero_bounds_var; +} + +/* Return bounds used as returned by call + which produced SSA name VAL. */ +gimple +chkp_retbnd_call_by_val (tree val) +{ + if (TREE_CODE (val) != SSA_NAME) + return NULL; + + gcc_assert (gimple_code (SSA_NAME_DEF_STMT (val)) == GIMPLE_CALL); + + imm_use_iterator use_iter; + use_operand_p use_p; + FOR_EACH_IMM_USE_FAST (use_p, use_iter, val) + if (gimple_code (USE_STMT (use_p)) == GIMPLE_CALL + && gimple_call_fndecl (USE_STMT (use_p)) == chkp_ret_bnd_fndecl) + return USE_STMT (use_p); + + return NULL; +} + +/* Build and return CALL_EXPR for bndstx builtin with specified + arguments. */ +tree +chkp_build_bndldx_call (tree addr, tree ptr) +{ + tree fn = build1 (ADDR_EXPR, + build_pointer_type (TREE_TYPE (chkp_bndldx_fndecl)), + chkp_bndldx_fndecl); + tree call = build_call_nary (TREE_TYPE (TREE_TYPE (chkp_bndldx_fndecl)), + fn, 2, addr, ptr); + CALL_WITH_BOUNDS_P (call) = true; + return call; +} + +/* Build and return CALL_EXPR for bndstx builtin with specified + arguments. */ +tree +chkp_build_bndstx_call (tree addr, tree ptr, tree bounds) +{ + tree fn = build1 (ADDR_EXPR, + build_pointer_type (TREE_TYPE (chkp_bndstx_fndecl)), + chkp_bndstx_fndecl); + tree call = build_call_nary (TREE_TYPE (TREE_TYPE (chkp_bndstx_fndecl)), + fn, 3, ptr, bounds, addr); + CALL_WITH_BOUNDS_P (call) = true; + return call; +} + +/* Insert code to store BOUNDS for PTR stored by ADDR. + New statements are inserted after position pointed + by GSI. */ +void +chkp_build_bndstx (tree addr, tree ptr, tree bounds, + gimple_stmt_iterator *gsi) +{ + gimple_seq seq; + gimple stmt; + + seq = NULL; + + addr = chkp_force_gimple_call_op (addr, &seq); + ptr = chkp_force_gimple_call_op (ptr, &seq); + + stmt = gimple_build_call (chkp_bndstx_fndecl, 3, ptr, bounds, addr); + chkp_mark_stmt (stmt); + gimple_call_set_with_bounds (stmt, true); + + gimple_seq_add_stmt (&seq, stmt); + + gsi_insert_seq_after (gsi, seq, GSI_CONTINUE_LINKING); + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Generated bndstx for pointer store "); + print_gimple_stmt (dump_file, gsi_stmt (*gsi), 0, TDF_VOPS|TDF_MEMSYMS); + print_gimple_stmt (dump_file, stmt, 2, TDF_VOPS|TDF_MEMSYMS); + } +} + +/* Return CALL_EXPR for bndmk with specified LOWER_BOUND and SIZE. */ +tree +chkp_build_make_bounds_call (tree lower_bound, tree size) +{ + tree call = build1 (ADDR_EXPR, + build_pointer_type (TREE_TYPE (chkp_bndmk_fndecl)), + chkp_bndmk_fndecl); + return build_call_nary (TREE_TYPE (TREE_TYPE (chkp_bndmk_fndecl)), + call, 2, lower_bound, size); +} + +/* Return 1 if TYPE has fields with zero size or fields + marked with chkp_variable_size attribute. */ +bool +chkp_variable_size_type (tree type) +{ + bool res = false; + tree field; + + if (RECORD_OR_UNION_TYPE_P (type)) + for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) + { + if (TREE_CODE (field) == FIELD_DECL) + res = res + || lookup_attribute ("bnd_variable_size", DECL_ATTRIBUTES (field)) + || chkp_variable_size_type (TREE_TYPE (field)); + } + else + res = !TYPE_SIZE (type) + || TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST + || tree_to_uhwi (TYPE_SIZE (type)) == 0; + + return res; +} + +#include "gt-tree-chkp.h" diff --git a/gcc/tree-chkp.h b/gcc/tree-chkp.h new file mode 100644 index 0000000..0357658 --- /dev/null +++ b/gcc/tree-chkp.h @@ -0,0 +1,51 @@ +/* Declaration of interface functions of Pointer Bounds Checker. + Copyright (C) 2014 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC 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, or (at your option) any later +version. + +GCC 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 GCC; see the file COPYING3. If not see +. */ + +#ifndef GCC_TREE_CHKP_H +#define GCC_TREE_CHKP_H + +#include "tree.h" +#include "cgraph.h" + +#define DECL_BOUNDS(NODE) (chkp_get_bounds (DECL_WRTL_CHECK (NODE))) + +#define SET_DECL_BOUNDS(NODE, VAL) \ + (chkp_set_bounds (DECL_WRTL_CHECK (NODE), VAL)) + +extern tree chkp_get_bounds (tree node); +extern void chkp_set_bounds (tree node, tree val); +extern bool chkp_type_has_pointer (const_tree type); +extern unsigned chkp_type_bounds_count (const_tree type); +extern tree chkp_make_bounds_for_struct_addr (tree ptr); +extern tree chkp_get_zero_bounds_var (void); +extern bool chkp_variable_size_type (tree type); +extern tree chkp_build_make_bounds_call (tree lb, tree size); +extern tree chkp_build_bndldx_call (tree addr, tree ptr); +extern tree chkp_build_bndstx_call (tree addr, tree ptr, tree bounds); +extern bitmap chkp_find_bound_slots (const_tree type); +extern void chkp_build_bndstx (tree addr, tree ptr, tree bounds, + gimple_stmt_iterator *gsi); +extern gimple chkp_retbnd_call_by_val (tree val); +extern bool chkp_function_instrumented_p (tree fndecl); +extern void chkp_function_mark_instrumented (tree fndecl); +extern bool chkp_gimple_call_builtin_p (gimple call, + enum built_in_function code); +extern void chkp_expand_bounds_reset_for_mem (tree mem, tree ptr); + +#endif /* GCC_TREE_CHKP_H */