This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

gcc stack-smashing protector (for gcc-3.0 20010507)


 This patch introduces -fstack-protector option, which is a stack-smashing 
protection mechanism to the latest snapshot (3.0 20010507).
This patch and new files (protector.h and protector.c) are bootstraped
and tested on i386-pc-linux-gnu and powerpc-ibm-aix4.3.3.0.

Please see the web page
(http://www.trl.ibm.co.jp/projects/security/ssp/) for details and
what is a stack-smashing protection.

Hiroaki Etoh,  Tokyo Research Laboratory, IBM Japan

2001-05-18  Hiroaki Etoh  <etoh@jp.ibm.com>

	* Add -fstack-protector option, which enables generating the stack
	protection code to detect buffer overflow and the stop its
	execution
	
	* protector.c: New file
	* protector.h: New file

	* Makefile.in: Add new file protector.c and new library member
	_stack_smash_handler in libgcc2.c
	* builtins.c (get_memory_rtx): Specify EXPAND_NORMAL as an argument of
	expand_expr in the case of using stack smashing protection
	* cse.c (cse_insn): Don't record equivalence of the register that
	duplicates a pointer in a function argument to prevent the corruption
	of buffer overflow
	* dbxout.c (dbxout_parms): Change the debug info of duplicated
	pointer argument in the case of using stack smashing protection
	* expr.c (expand_expr):  Specify ro_modifier in stead of EXPAND_SUM as
	an argument of expand_expr in the case of stack smashing protection
	* function.c (assign_stack_temp_for_type, combine_temp_slots): Add the
	special handling of character buffer for the reuse of
	allocated stack space
	* function.c (put_reg_into_stack): Change the location of allocated
	stack area for the spilled-out pseuso register in the case of stack
	smashing protection
	* gcse.c (cprop_insn): Don't eliminate the register that duplicates
	a pointer in a function argument to prevent the corruption
	of buffer overflow
	* integrate.c (expand_inline_function): Specify EXPAND_NORMAL as an
	argument of expand_expr in the case of using stack smashing protection
	* libgcc2.c (__guard_setup, __stack_smash_handler): New function.
	* reload1.c (alter_reg): Change the location of allocated stack area
	for the spilled-out pseuso register in the case of
	stack smashing protection
	* toplev.c (rest_of_compilation, f_options): Add the function of
	stack smashing protection
Index: gcc/Makefile.in
===================================================================
RCS file: /home/cvsroot/gcc/gcc/Makefile.in,v
retrieving revision 1.1.1.3
retrieving revision 1.1.1.3.2.1
diff -c -3 -p -r1.1.1.3 -r1.1.1.3.2.1
*** gcc/Makefile.in	2001/05/14 04:50:48	1.1.1.3
--- gcc/Makefile.in	2001/05/14 05:23:59	1.1.1.3.2.1
*************** OBJS = diagnostic.o version.o tree.o pri
*** 752,758 ****
   mbchar.o splay-tree.o graph.o sbitmap.o resource.o hash.o predict.o	      \
   lists.o ggc-common.o $(GGC) stringpool.o simplify-rtx.o ssa.o bb-reorder.o   \
   sibcall.o conflict.o timevar.o ifcvt.o dominance.o dependence.o dce.o \
!  sched-vis.o sched-deps.o sched-rgn.o sched-ebb.o params.o
  
  BACKEND = toplev.o libbackend.a
  
--- 752,758 ----
   mbchar.o splay-tree.o graph.o sbitmap.o resource.o hash.o predict.o	      \
   lists.o ggc-common.o $(GGC) stringpool.o simplify-rtx.o ssa.o bb-reorder.o   \
   sibcall.o conflict.o timevar.o ifcvt.o dominance.o dependence.o dce.o \
!  sched-vis.o sched-deps.o sched-rgn.o sched-ebb.o params.o protector.o
  
  BACKEND = toplev.o libbackend.a
  
*************** LIB2FUNCS = _muldi3 _divdi3 _moddi3 _udi
*** 803,809 ****
      _bb _clear_cache _trampoline __main _exit \
      _absvsi2 _absvdi2 _addvsi3 _addvdi3 _subvsi3 _subvdi3 \
      _mulvsi3 _mulvdi3 _negvsi2 _negvdi2 \
!     _ctors
  
  LIB2FUNCS_EH = _eh
  
--- 803,809 ----
      _bb _clear_cache _trampoline __main _exit \
      _absvsi2 _absvdi2 _addvsi3 _addvdi3 _subvsi3 _subvdi3 \
      _mulvsi3 _mulvdi3 _negvsi2 _negvdi2 \
!     _ctors _stack_smash_handler
  
  LIB2FUNCS_EH = _eh
  
Index: gcc/builtins.c
===================================================================
RCS file: /home/cvsroot/gcc/gcc/builtins.c,v
retrieving revision 1.1.1.1
retrieving revision 1.1.1.1.2.1
diff -c -3 -p -r1.1.1.1 -r1.1.1.1.2.1
*** gcc/builtins.c	2001/05/14 04:50:48	1.1.1.1
--- gcc/builtins.c	2001/05/14 05:23:59	1.1.1.1.2.1
*************** Boston, MA 02111-1307, USA.  */
*** 39,44 ****
--- 39,45 ----
  #include "typeclass.h"
  #include "toplev.h"
  #include "tm_p.h"
+ #include "protector.h"
  
  #define CALLED_AS_BUILT_IN(NODE) \
     (!strncmp (IDENTIFIER_POINTER (DECL_NAME (NODE)), "__builtin_", 10))
*************** get_memory_rtx (exp)
*** 738,744 ****
    rtx mem = gen_rtx_MEM (BLKmode,
  			 memory_address (BLKmode,
  					 expand_expr (exp, NULL_RTX,
! 						      ptr_mode, EXPAND_SUM)));
  
    /* Get an expression we can use to find the attributes to assign to MEM.
       If it is an ADDR_EXPR, use the operand.  Otherwise, dereference it if
--- 739,745 ----
    rtx mem = gen_rtx_MEM (BLKmode,
  			 memory_address (BLKmode,
  					 expand_expr (exp, NULL_RTX,
! 						      ptr_mode, flag_propolice_protection?EXPAND_NORMAL:EXPAND_SUM)));
  
    /* Get an expression we can use to find the attributes to assign to MEM.
       If it is an ADDR_EXPR, use the operand.  Otherwise, dereference it if
Index: gcc/cse.c
===================================================================
RCS file: /home/cvsroot/gcc/gcc/cse.c,v
retrieving revision 1.1.1.3
retrieving revision 1.1.1.3.2.1
diff -c -3 -p -r1.1.1.3 -r1.1.1.3.2.1
*** gcc/cse.c	2001/05/14 04:50:51	1.1.1.3
--- gcc/cse.c	2001/05/14 05:24:00	1.1.1.3.2.1
*************** Boston, MA 02111-1307, USA.  */
*** 38,43 ****
--- 38,44 ----
  #include "toplev.h"
  #include "output.h"
  #include "ggc.h"
+ #include "protector.h"
  
  /* The basic idea of common subexpression elimination is to go
     through the code, keeping a record of expressions that would
*************** cse_insn (insn, libcall_insn)
*** 4776,4781 ****
--- 4777,4785 ----
        if (SET_DEST (x) == pc_rtx
  	  && GET_CODE (SET_SRC (x)) == LABEL_REF)
  	;
+       /* cut the reg propagation of stack-protected argument */
+       else if (x->volatil)
+ 	make_new_qty (REGNO (SET_DEST (x)), GET_MODE (SET_DEST (x)));
  
        /* Don't count call-insns, (set (reg 0) (call ...)), as a set.
  	 The hard function value register is used only once, to copy to
*************** cse_insn (insn, libcall_insn)
*** 6286,6291 ****
--- 6290,6299 ----
  	      rtx dest = SET_DEST (sets[0].rtl);
  	      rtx src = SET_SRC (sets[0].rtl);
  	      rtx note;
+ 
+ 	      /* update the debug info of stack-protected argument */
+ 	      if (PATTERN (prev)->volatil)
+ 		set_debuginfo_of_escaped_arg (dest,SET_DEST (PATTERN (prev)));
  
  	      validate_change (prev, &SET_DEST (PATTERN (prev)), dest, 1);
  	      validate_change (insn, &SET_DEST (sets[0].rtl), src, 1);
Index: gcc/dbxout.c
===================================================================
RCS file: /home/cvsroot/gcc/gcc/dbxout.c,v
retrieving revision 1.1.1.2
retrieving revision 1.1.1.2.2.1
diff -c -3 -p -r1.1.1.2 -r1.1.1.2.2.1
*** gcc/dbxout.c	2001/05/14 04:50:52	1.1.1.2
--- gcc/dbxout.c	2001/05/14 05:24:00	1.1.1.2.2.1
*************** dbxout_parms (parms)
*** 2322,2327 ****
--- 2322,2330 ----
    for (; parms; parms = TREE_CHAIN (parms))
      if (DECL_NAME (parms) && TREE_TYPE (parms) != error_mark_node)
        {
+ 	/* change the debug info of escaped argument for stack protection */
+ 	update_debuginfo_using_escaped_arg_list (parms);
+ 	
  	dbxout_prepare_symbol (parms);
  
  	/* Perform any necessary register eliminations on the parameter's rtl,
Index: gcc/expr.c
===================================================================
RCS file: /home/cvsroot/gcc/gcc/expr.c,v
retrieving revision 1.1.1.3
retrieving revision 1.1.1.3.2.1
diff -c -3 -p -r1.1.1.3 -r1.1.1.3.2.1
*** gcc/expr.c	2001/05/14 04:50:53	1.1.1.3
--- gcc/expr.c	2001/05/14 05:24:00	1.1.1.3.2.1
*************** Boston, MA 02111-1307, USA.  */
*** 43,48 ****
--- 43,49 ----
  #include "ggc.h"
  #include "intl.h"
  #include "tm_p.h"
+ #include "protector.h"
  
  #ifndef ACCUMULATE_OUTGOING_ARGS
  #define ACCUMULATE_OUTGOING_ARGS 0
*************** expand_expr (exp, target, tmode, modifie
*** 6643,6649 ****
   	  return
  	    GEN_INT (TREE_STRING_POINTER (string)[TREE_INT_CST_LOW (index)]);
  
! 	op0 = expand_expr (exp1, NULL_RTX, VOIDmode, EXPAND_SUM);
  	op0 = memory_address (mode, op0);
  
  	if (cfun && current_function_check_memory_usage
--- 6644,6650 ----
   	  return
  	    GEN_INT (TREE_STRING_POINTER (string)[TREE_INT_CST_LOW (index)]);
  
! 	op0 = expand_expr (exp1, NULL_RTX, VOIDmode, flag_propolice_protection?ro_modifier:EXPAND_SUM);
  	op0 = memory_address (mode, op0);
  
  	if (cfun && current_function_check_memory_usage
Index: gcc/function.c
===================================================================
RCS file: /home/cvsroot/gcc/gcc/function.c,v
retrieving revision 1.1.1.3
retrieving revision 1.1.1.3.2.1
diff -c -3 -p -r1.1.1.3 -r1.1.1.3.2.1
*** gcc/function.c	2001/05/14 04:51:01	1.1.1.3
--- gcc/function.c	2001/05/14 05:24:01	1.1.1.3.2.1
*************** Boston, MA 02111-1307, USA.  */
*** 59,64 ****
--- 59,65 ----
  #include "hash.h"
  #include "ggc.h"
  #include "tm_p.h"
+ #include "protector.h"
  
  #ifndef ACCUMULATE_OUTGOING_ARGS
  #define ACCUMULATE_OUTGOING_ARGS 0
*************** static varray_type epilogue;
*** 161,166 ****
--- 162,171 ----
  /* Array of INSN_UIDs to hold the INSN_UIDs for each sibcall epilogue
     in this function.  */
  static varray_type sibcall_epilogue;
+ 
+ /* Current boundary mark for character arrays.  */
+ int temp_boundary_mark = 0;
+ 
  
  /* In order to evaluate some expressions, such as function calls returning
     structures in memory, we need to temporarily allocate stack locations.
*************** struct temp_slot
*** 214,219 ****
--- 219,226 ----
    /* The size of the slot, including extra space for alignment.  This
       info is for combine_temp_slots.  */
    HOST_WIDE_INT full_size;
+   /* Boundary mark of a character array and the others. This info is for ProPolice */
+   int boundary_mark;
  };
  
  /* This structure is used to record MEMs or pseudos used to replace VAR, any
*************** assign_stack_temp_for_type (mode, size, 
*** 656,661 ****
--- 663,671 ----
  {
    int align;
    struct temp_slot *p, *best_p = 0;
+   int char_array = type && (TREE_TYPE (type)==char_type_node
+ 			    || TREE_TYPE (type)==signed_char_type_node
+ 			    || TREE_TYPE (type)==unsigned_char_type_node);
  
    /* If SIZE is -1 it means that somebody tried to allocate a temporary
       of a variable size.  */
*************** assign_stack_temp_for_type (mode, size, 
*** 681,687 ****
  	&& ! p->in_use
  	&& objects_must_conflict_p (p->type, type)
  	&& (best_p == 0 || best_p->size > p->size
! 	    || (best_p->size == p->size && best_p->align > p->align)))
        {
  	if (p->align == align && p->size == size)
  	  {
--- 691,698 ----
  	&& ! p->in_use
  	&& objects_must_conflict_p (p->type, type)
  	&& (best_p == 0 || best_p->size > p->size
! 	    || (best_p->size == p->size && best_p->align > p->align))
! 	&& (! char_array || p->boundary_mark != 0))
        {
  	if (p->align == align && p->size == size)
  	  {
*************** assign_stack_temp_for_type (mode, size, 
*** 716,721 ****
--- 727,733 ----
  	      p->address = 0;
  	      p->rtl_expr = 0;
  	      p->type = best_p->type;
+ 	      p->boundary_mark = best_p->boundary_mark;
  	      p->next = temp_slots;
  	      temp_slots = p;
  
*************** assign_stack_temp_for_type (mode, size, 
*** 776,781 ****
--- 788,794 ----
        p->full_size = frame_offset - frame_offset_old;
  #endif
        p->address = 0;
+       p->boundary_mark = char_array?++temp_boundary_mark:0;
        p->next = temp_slots;
        temp_slots = p;
      }
*************** combine_temp_slots ()
*** 924,937 ****
  	    int delete_q = 0;
  	    if (! q->in_use && GET_MODE (q->slot) == BLKmode)
  	      {
! 		if (p->base_offset + p->full_size == q->base_offset)
  		  {
  		    /* Q comes after P; combine Q into P.  */
  		    p->size += q->size;
  		    p->full_size += q->full_size;
  		    delete_q = 1;
  		  }
! 		else if (q->base_offset + q->full_size == p->base_offset)
  		  {
  		    /* P comes after Q; combine P into Q.  */
  		    q->size += p->size;
--- 937,952 ----
  	    int delete_q = 0;
  	    if (! q->in_use && GET_MODE (q->slot) == BLKmode)
  	      {
! 		if (p->base_offset + p->full_size == q->base_offset &&
! 		    p->boundary_mark == q->boundary_mark)
  		  {
  		    /* Q comes after P; combine Q into P.  */
  		    p->size += q->size;
  		    p->full_size += q->full_size;
  		    delete_q = 1;
  		  }
! 		else if (q->base_offset + q->full_size == p->base_offset &&
! 			 p->boundary_mark == q->boundary_mark)
  		  {
  		    /* P comes after Q; combine P into Q.  */
  		    q->size += p->size;
*************** put_reg_into_stack (function, reg, type,
*** 1485,1491 ****
      new = func->x_parm_reg_stack_loc[regno];
  
    if (new == 0)
!     new = assign_stack_local_1 (decl_mode, GET_MODE_SIZE (decl_mode), 0, func);
  
    PUT_CODE (reg, MEM);
    PUT_MODE (reg, decl_mode);
--- 1500,1508 ----
      new = func->x_parm_reg_stack_loc[regno];
  
    if (new == 0)
!     new = function ?
! 	assign_stack_local_1 (decl_mode, GET_MODE_SIZE (decl_mode), 0, func):
! 	assign_stack_local_for_pseudo_reg (decl_mode, GET_MODE_SIZE (decl_mode), 0);
  
    PUT_CODE (reg, MEM);
    PUT_MODE (reg, decl_mode);
*************** reposition_prologue_and_epilogue_notes (
*** 7545,7550 ****
--- 7562,7573 ----
  	}
      }
  #endif /* HAVE_prologue or HAVE_epilogue */
+ }
+ 
+ tree
+ query_trampoline_list()
+ {
+     return trampoline_list;
  }
  
  /* Mark T for GC.  */
Index: gcc/function.h
===================================================================
RCS file: /home/cvsroot/gcc/gcc/function.h,v
retrieving revision 1.1.1.2
retrieving revision 1.1.1.2.2.1
diff -c -3 -p -r1.1.1.2 -r1.1.1.2.2.1
*** gcc/function.h	2001/05/14 04:51:02	1.1.1.2
--- gcc/function.h	2001/05/14 05:24:01	1.1.1.2.2.1
*************** extern void init_virtual_regs		PARAMS ((
*** 597,602 ****
--- 597,605 ----
  /* Called once, at initialization, to initialize function.c.  */
  extern void init_function_once          PARAMS ((void));
  
+ /* List of trampolines, used in protector.c */
+ extern tree query_trampoline_list	PARAMS ((void));
+ 
  #ifdef rtx
  #undef rtx
  #endif
Index: gcc/gcse.c
===================================================================
RCS file: /home/cvsroot/gcc/gcc/gcse.c,v
retrieving revision 1.1.1.2
retrieving revision 1.1.1.2.2.1
diff -c -3 -p -r1.1.1.2 -r1.1.1.2.2.1
*** gcc/gcse.c	2001/05/14 04:50:55	1.1.1.2
--- gcc/gcse.c	2001/05/14 05:24:01	1.1.1.2.2.1
*************** cprop_insn (insn, alter_jumps)
*** 3908,3914 ****
        /* Find an assignment that sets reg_used and is available
  	 at the start of the block.  */
        set = find_avail_set (regno, insn);
!       if (! set)
  	continue;
    
        pat = set->expr;
--- 3908,3914 ----
        /* Find an assignment that sets reg_used and is available
  	 at the start of the block.  */
        set = find_avail_set (regno, insn);
!       if (! set || set->expr->volatil)
  	continue;
    
        pat = set->expr;
Index: gcc/integrate.c
===================================================================
RCS file: /home/cvsroot/gcc/gcc/integrate.c,v
retrieving revision 1.1.1.2
retrieving revision 1.1.1.2.2.1
diff -c -3 -p -r1.1.1.2 -r1.1.1.2.2.1
*** gcc/integrate.c	2001/05/14 04:50:54	1.1.1.2
--- gcc/integrate.c	2001/05/14 05:24:01	1.1.1.2.2.1
*************** Boston, MA 02111-1307, USA.  */
*** 41,46 ****
--- 41,47 ----
  #include "intl.h"
  #include "loop.h"
  #include "params.h"
+ #include "protector.h"
  
  #include "obstack.h"
  #define	obstack_chunk_alloc	xmalloc
*************** expand_inline_function (fndecl, parms, t
*** 727,736 ****
  	    arg_vals[i] = convert_modes (GET_MODE (loc),
  					 TYPE_MODE (TREE_TYPE (arg)),
  					 expand_expr (arg, NULL_RTX, mode,
! 						      EXPAND_SUM),
  					 TREE_UNSIGNED (TREE_TYPE (formal)));
  	  else
! 	    arg_vals[i] = expand_expr (arg, NULL_RTX, mode, EXPAND_SUM);
  	}
        else
  	arg_vals[i] = 0;
--- 728,737 ----
  	    arg_vals[i] = convert_modes (GET_MODE (loc),
  					 TYPE_MODE (TREE_TYPE (arg)),
  					 expand_expr (arg, NULL_RTX, mode,
! 						      flag_propolice_protection?EXPAND_NORMAL:EXPAND_SUM),
  					 TREE_UNSIGNED (TREE_TYPE (formal)));
  	  else
! 	    arg_vals[i] = expand_expr (arg, NULL_RTX, mode, flag_propolice_protection?EXPAND_NORMAL:EXPAND_SUM);
  	}
        else
  	arg_vals[i] = 0;
Index: gcc/libgcc-std.ver
===================================================================
RCS file: /home/cvsroot/gcc/gcc/libgcc-std.ver,v
retrieving revision 1.1.1.1
retrieving revision 1.1.1.1.2.1
diff -c -3 -p -r1.1.1.1 -r1.1.1.1.2.1
*** gcc/libgcc-std.ver	2001/05/14 04:50:57	1.1.1.1
--- gcc/libgcc-std.ver	2001/05/15 05:34:16	1.1.1.1.2.1
*************** GCC_3.0 {
*** 135,138 ****
--- 135,142 ----
    __throw
    __throw_type_match
    __unwinding_cleanup
+ 
+   # stack smash handler symbols
+   __guard
+   __stack_smash_handler
  }
Index: gcc/libgcc2.c
===================================================================
RCS file: /home/cvsroot/gcc/gcc/libgcc2.c,v
retrieving revision 1.1.1.2
retrieving revision 1.1.1.2.2.2
diff -c -3 -p -r1.1.1.2 -r1.1.1.2.2.2
*** gcc/libgcc2.c	2001/05/14 04:51:02	1.1.1.2
--- gcc/libgcc2.c	2001/05/16 02:48:50	1.1.1.2.2.2
*************** __throw ()
*** 4115,4117 ****
--- 4115,4188 ----
  #endif /* IA64_UNWIND_INFO  */
  
  #endif /* L_eh */
+ 
+ #ifdef L_stack_smash_handler
+ #include <stdio.h>
+ #include <string.h>
+ #include <fcntl.h>
+ 
+ #if defined(HAVE_SYSLOG)
+ #include <sys/types.h>
+ #include <sys/socket.h>
+ #include <sys/un.h>
+ 
+ #include <sys/syslog.h>
+ #ifndef _PATH_LOG
+ #define _PATH_LOG "/dev/log"
+ #endif
+ #endif
+ 
+ char __guard[32] = {0,0,0,0,0,0,0,0};
+ static void __guard_setup (void) __attribute__ ((constructor)) ;
+ static void __guard_setup (void)
+ {
+   int fd;
+   if (((int*)__guard)[0]!=0) return;
+   fd = open ("/dev/urandom", 0);
+   if (fd != -1) {
+     ssize_t size = read (fd, &__guard, sizeof(__guard));
+     close (fd) ;
+     if (size == sizeof(__guard)) return;
+   }
+   /* If a random generator can't be used, the protector switches the guard
+      to the "terminator canary" */
+   __guard[0] = 0; __guard[1] = 0; __guard[2] = '\n'; __guard[3] = 255;
+ }
+ void __stack_smash_handler (char func[], int damaged)
+ {
+ #if defined (__GNU_LIBRARY__)
+   extern char * __progname;
+ #endif
+   char message[] = ": stack smashing attack in function ";
+   int bufsz = 256, len;
+   char buf[bufsz];
+ #if defined(HAVE_SYSLOG)
+   int LogFile;
+   struct sockaddr_un SyslogAddr;  /* AF_UNIX address of local logger */
+ #endif
+ 
+   strcpy(buf, "<2>"); len=3;	/* send LOG_CRIT */
+ #if defined (__GNU_LIBRARY__)
+   strncat(buf, __progname, bufsz-len); len = strlen(buf);
+ #endif
+   if (bufsz>len) strncat(buf, message, bufsz-len); len = strlen(buf);
+   if (bufsz>len) strncat(buf, func, bufsz-len); len = strlen(buf);
+ 
+   /* print error message */
+   write (STDERR_FILENO, buf+3, len-3);
+ #if defined(HAVE_SYSLOG)
+   if ((LogFile = socket(AF_UNIX, SOCK_DGRAM, 0)) != -1) {
+ 
+     /*
+      * Send "found" message to the "/dev/log" path
+      */
+     SyslogAddr.sun_family = AF_UNIX;
+     (void)strncpy(SyslogAddr.sun_path, _PATH_LOG,
+ 		  sizeof SyslogAddr.sun_path);
+     sendto(LogFile, buf, strlen(buf), 0, (struct sockaddr *)&SyslogAddr, sizeof(SyslogAddr));
+   }
+ #endif
+   abort();
+ }
+ #endif
+ 
Index: gcc/reload1.c
===================================================================
RCS file: /home/cvsroot/gcc/gcc/reload1.c,v
retrieving revision 1.1.1.3
retrieving revision 1.1.1.3.2.1
diff -c -3 -p -r1.1.1.3 -r1.1.1.3.2.1
*** gcc/reload1.c	2001/05/14 04:51:02	1.1.1.3
--- gcc/reload1.c	2001/05/14 05:24:02	1.1.1.3.2.1
*************** Boston, MA 02111-1307, USA.  */
*** 41,46 ****
--- 41,47 ----
  #include "cselib.h"
  #include "real.h"
  #include "toplev.h"
+ #include "protector.h"
  
  #if !defined PREFERRED_STACK_BOUNDARY && defined STACK_BOUNDARY
  #define PREFERRED_STACK_BOUNDARY STACK_BOUNDARY
*************** alter_reg (i, from_reg)
*** 1977,1983 ****
        if (from_reg == -1)
  	{
  	  /* No known place to spill from => no slot to reuse.  */
! 	  x = assign_stack_local (GET_MODE (regno_reg_rtx[i]), total_size,
  				  inherent_size == total_size ? 0 : -1);
  	  if (BYTES_BIG_ENDIAN)
  	    /* Cancel the  big-endian correction done in assign_stack_local.
--- 1978,1984 ----
        if (from_reg == -1)
  	{
  	  /* No known place to spill from => no slot to reuse.  */
! 	  x = assign_stack_local_for_pseudo_reg (GET_MODE (regno_reg_rtx[i]), total_size,
  				  inherent_size == total_size ? 0 : -1);
  	  if (BYTES_BIG_ENDIAN)
  	    /* Cancel the  big-endian correction done in assign_stack_local.
Index: gcc/toplev.c
===================================================================
RCS file: /home/cvsroot/gcc/gcc/toplev.c,v
retrieving revision 1.1.1.3
retrieving revision 1.1.1.3.2.1
diff -c -3 -p -r1.1.1.3 -r1.1.1.3.2.1
*** gcc/toplev.c	2001/05/14 04:51:02	1.1.1.3
--- gcc/toplev.c	2001/05/14 05:24:02	1.1.1.3.2.1
*************** int align_labels_log;
*** 904,909 ****
--- 904,916 ----
  int align_functions;
  int align_functions_log;
  
+ #ifdef STACK_PROTECTOR
+ /* Nonzero means use ProPolice as a stack protection method */
+ int flag_propolice_protection = 1;
+ #else
+ int flag_propolice_protection = 0;
+ #endif
+ 
  /* Table of supported debugging formats.  */
  static struct
  {
*************** lang_independent_options f_options[] =
*** 1162,1167 ****
--- 1169,1178 ----
     "Report on permanent memory allocation at end of run"},
    { "trapv", &flag_trapv, 1,
      "Trap for signed overflow in addition / subtraction / multiplication." },
+   {"stack-protector", &flag_propolice_protection, 1,
+    "Enables stack protection" },
+   {"no-stack-protector", &flag_propolice_protection, 0,
+    "Disables stack protection" },
  };
  
  /* Table of language-specific options.  */
*************** rest_of_compilation (decl)
*** 2796,2801 ****
--- 2807,2814 ----
  
        insns = get_insns ();
  
+       if (flag_propolice_protection) prepare_stack_protection ();
+   
        /* Dump the rtl code if we are dumping rtl.  */
  
        if (open_dump_file (DFI_rtl, decl))
Index: gcc/config/t-linux
===================================================================
RCS file: /home/cvsroot/gcc/gcc/config/t-linux,v
retrieving revision 1.1.1.3
retrieving revision 1.1.1.2
diff -c -3 -p -r1.1.1.3 -r1.1.1.2
*** gcc/config/t-linux	2001/05/14 05:17:31	1.1.1.3
--- gcc/config/t-linux	2001/05/14 04:51:08	1.1.1.2
*************** INSTALL_ASSERT_H =
*** 7,13 ****
  # Compile crtbeginS.o and crtendS.o with pic.
  CRTSTUFF_T_CFLAGS_S = -fPIC
  # Compile libgcc2.a with pic.
! TARGET_LIBGCC2_CFLAGS = -fPIC
  # Build a shared libgcc library.
  SHLIB_EXT = .so
  SHLIB_LINK = $(GCC_FOR_TARGET) $(LIBGCC2_CFLAGS) -shared -nodefaultlibs \
--- 7,13 ----
  # Compile crtbeginS.o and crtendS.o with pic.
  CRTSTUFF_T_CFLAGS_S = -fPIC
  # Compile libgcc2.a with pic.
! TARGET_LIBGCC2_CFLAGS = -fPIC -DHAVE_SYSLOG
  # Build a shared libgcc library.
  SHLIB_EXT = .so
  SHLIB_LINK = $(GCC_FOR_TARGET) $(LIBGCC2_CFLAGS) -shared -nodefaultlibs \
/* Top level of GNU C compiler
   Copyright (C) 1987, 88, 89, 92-7, 1998 Free Software Foundation, Inc.

This file is part of GNU CC.

GNU CC 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 2, or (at your option)
any later version.

GNU CC 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 GNU CC; see the file COPYING.  If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.  */

#include "config.h"
#include "system.h"

#include "rtl.h"
#include "tree.h"
#include "regs.h"
#include "flags.h"
#include "insn-config.h"
#include "insn-flags.h"
#include "expr.h"
#include "output.h"
#include "recog.h"
#include "hard-reg-set.h"
#include "real.h"
#include "except.h"
#include "function.h"
#include "toplev.h"
#include "conditions.h"
#include "insn-attr.h"
#include "c-tree.h"
#include "protector.h"


rtx assign_stack_local_for_pseudo_reg PARAMS ((enum machine_mode, HOST_WIDE_INT, int));
void set_debuginfo_of_escaped_arg PARAMS ((rtx old, rtx new));
void update_debuginfo_using_escaped_arg_list PARAMS ((tree parms));


/* Round a value to the lowest integer less than it that is a multiple of
   the required alignment.  Avoid using division in case the value is
   negative.  Assume the alignment is a power of two.  */
#define FLOOR_ROUND(VALUE,ALIGN) ((VALUE) & ~((ALIGN) - 1))

/* Similar, but round to the next highest integer that meets the
   alignment.  */
#define CEIL_ROUND(VALUE,ALIGN)	(((VALUE) + (ALIGN) - 1) & ~((ALIGN)- 1))


/* Nonzero means use propolice as a stack protection method */
extern int flag_propolice_protection;

/* List of trampolines */
extern tree query_trampoline_list PARAMS ((void));

typedef struct { rtx original; rtx escaped; } arg_status;

/* This file contains several memory arrangement functions to protect
   the return address and the frame pointer of the stack
   from a stack-smashing attack. It also
   provides the function that protects pointer variables. */

/* Nonzero if function being compiled can define string buffers that may be
   damaged by the stack-smash attack */
static int current_function_defines_vulnerable_string;
static int current_function_has_variable_string;

static rtx guard_area, _guard;
static rtx function_first_insn, prologue_insert_point;

/*  */
static HOST_WIDE_INT sweep_frame_offset;
static arg_status* escaped_arg_list = 0;
static int escaped_arg_list_size = 0;
static int guard_has_legitimate_address;

static int search_string_from_argsandvars PARAMS ((void));
static int search_string_from_local_vars PARAMS ((tree block));
static int search_string_def PARAMS ((tree names));
static int search_pointer_def PARAMS ((tree names));
static int search_func_pointer PARAMS ((tree type, int mark));
static void reset_used_flags_for_insns PARAMS ((rtx insn));
static void reset_used_flags_for_decls PARAMS ((tree block));
static void reset_used_flags_of_plus PARAMS ((rtx x));
static void rtl_prologue PARAMS ((rtx insn));
static void rtl_epilogue PARAMS ((rtx fnlastinsn));
static void arrange_var_order PARAMS ((tree blocks));
static void copy_args_for_protection PARAMS ((void));
static void sweep_string_variable PARAMS ((rtx sweep_var, int var_size));
static void sweep_string_in_decls PARAMS ((tree block, int sweep_offset, int size));
static void sweep_string_in_args PARAMS ((tree parms, int sweep_offset, int size));
static void sweep_string_use_of_insns PARAMS ((rtx insn, int sweep_offset, int size));
static void sweep_string_in_operand PARAMS ((rtx orig, int sweep_offset, int size));
static void move_arg_location PARAMS ((rtx insn, rtx orig, rtx new, int var_size));
static void change_arg_use_of_insns PARAMS ((rtx insn, rtx orig, rtx new, int size));
static void change_arg_use_in_operand PARAMS ((rtx x, rtx orig, rtx new, int size));


#define SUSPICIOUS_BUF_SIZE 8

#define DEBUGGER_AUTO_BASEPTR(X) \
  (GET_CODE (X) == PLUS ? XEXP (X, 0) : X)
#define DEBUGGER_AUTO_OFFSET(X) \
  (GET_CODE (X) == PLUS ? INTVAL (XEXP (X, 1)) : 0)
#define PARM_PASSED_IN_MEMORY(PARM) \
 (GET_CODE (DECL_INCOMING_RTL (PARM)) == MEM)



void
prepare_stack_protection (void)
{
  tree blocks = DECL_INITIAL (current_function_decl);
  current_function_has_variable_string = FALSE;

  /*
    skip the protection if the function has no block or it is an inline function
  */
  if (! blocks || DECL_INLINE (current_function_decl)) return;

  current_function_defines_vulnerable_string = search_string_from_argsandvars ();

  if (current_function_defines_vulnerable_string)
    {
      HOST_WIDE_INT previous_frame_offset, offset;
      function_first_insn = get_insns ();

      if (query_trampoline_list ()) return;
    
      sweep_frame_offset = 0;
	
#ifdef STACK_GROWS_DOWNWARD
      /*
	frame_offset: offset to end of allocated area of stack frame.
	 It is defined in the function.c
      */
      previous_frame_offset = frame_offset;

      /* the location must be before buffers */
      guard_area = assign_stack_local (GUARD_m, UNITS_PER_GUARD, 0);
      MEM_VOLATILE_P (guard_area) = 1;
	
      /* check if the address of the guard has legitimate address */
      guard_has_legitimate_address = 1;
      GO_IF_LEGITIMATE_ADDRESS(GUARD_m, guard_area, has_legitimate_address);
      guard_has_legitimate_address = 0;
    has_legitimate_address:
	
#ifndef FRAME_GROWS_DOWNWARD
      sweep_frame_offset = frame_offset;
#endif

      /* For making room for guard value, scan all insns and fix the offset address
	 of the variable that is based on frame pointer.
	 Scan all declarations of variables and fix the offset address of the variable that
	 is based on the frame pointer */
      sweep_string_variable (guard_area, UNITS_PER_GUARD);

	
      /* the location of guard area moves to the beginning of stack frame */
      offset = DEBUGGER_AUTO_OFFSET(XEXP (guard_area, 0));
      XEXP (XEXP (guard_area, 0), 1) = gen_rtx_CONST_INT (VOIDmode, sweep_frame_offset);


      /* Insert prologue rtl instructions */
      rtl_prologue (function_first_insn);

      if (! current_function_has_variable_string)
	{
	  /* Generate argument saving instruction */
	  copy_args_for_protection ();

#ifndef FRAME_GROWS_DOWNWARD
	  /* If frame grows upward, character string copied from an arg stays top of
	     the guard variable. So sweep the guard variable again */
	  sweep_frame_offset = frame_offset;
	  sweep_string_variable (guard_area, UNITS_PER_GUARD);
#endif
	}
#endif

      if (! current_function_has_variable_string
	  && guard_has_legitimate_address)
	{
	  /* Arrange the order of local variables */
	  arrange_var_order (blocks);
	}

#ifdef STACK_GROWS_DOWNWARD
      /* Insert epilogue rtl instructions */
      rtl_epilogue (get_last_insn ());
#endif
    }
}


static int
search_string_from_argsandvars (void)
{
  tree blocks, parms;
  int string_p;

  /*
    search a string variable from local variables
  */
  blocks = DECL_INITIAL (current_function_decl);
  string_p = search_string_from_local_vars (blocks);
  if (string_p) return TRUE;


#ifdef FRAME_GROWS_DOWNWARD
  /*
    search a string variable from arguments
  */
  parms = DECL_ARGUMENTS (current_function_decl);

  for (; parms; parms = TREE_CHAIN (parms))
    if (DECL_NAME (parms) && TREE_TYPE (parms) != error_mark_node)
      {
	if (PARM_PASSED_IN_MEMORY (parms) && DECL_NAME (parms))
	  {
	    string_p = search_string_def (TREE_TYPE(parms));
	    if (string_p) return TRUE;
	  }
      }
#endif

  return FALSE;
}


static int
search_string_from_local_vars (block)
     tree block;
{
  tree types;
  int found = FALSE;

  while (block && TREE_CODE(block)==BLOCK)
    {
      types = BLOCK_VARS(block);

      while (types)
	{
	  /* skip the declaration that refers an external variable */
	  if (! DECL_EXTERNAL (types) && ! TREE_STATIC (types)
	      && TREE_CODE (types) == VAR_DECL
	      && DECL_RTL_SET_P (types) && GET_CODE (DECL_RTL (types)) == MEM)
	    {

	      if (search_string_def (TREE_TYPE (types)))
		{
		  rtx home = DECL_RTL (types);

		  if (GET_CODE (home) == MEM
		      && (GET_CODE (XEXP (home, 0)) == MEM
			  || (GET_CODE (XEXP (home, 0)) == REG
			      && REGNO (XEXP (home, 0)) != HARD_FRAME_POINTER_REGNUM
			      && REGNO (XEXP (home, 0)) != STACK_POINTER_REGNUM
#if ARG_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
			      && REGNO (XEXP (home, 0)) != ARG_POINTER_REGNUM
#endif
			      )))
		    /* If the value is indirect by memory or by a register
		       that isn't the frame pointer
		       then it means the object is variable-sized and address through
		       that register or stack slot.  The protection has no way to hide pointer variables
		       behind the array, so all we can do is staying the order of variables and arguments. */
		    {
		      current_function_has_variable_string = TRUE;
		    }
	    
		  found = TRUE;
		}
	    }

	  types = TREE_CHAIN(types);
	}

      if (search_string_from_local_vars (BLOCK_SUBBLOCKS (block)))
	{
	  found = TRUE;
	}

      block = BLOCK_CHAIN (block);
    }
    
  return found;
}

static int
search_string_def (type)
     tree type;
{
  tree tem;
    
  /* Mark it as defined, so that if it is self-referent
     we will not get into an infinite recursion of definitions.  */

  switch (TREE_CODE (type))
    {
    case ARRAY_TYPE:
      /* TREE_CODE( TREE_TYPE(type) ) == INTEGER_TYPE */
      if (TREE_TYPE(type) == char_type_node
	  || TREE_TYPE(type) == signed_char_type_node
	  || TREE_TYPE(type) == unsigned_char_type_node)
	{
	  /* Check if the string is a variable string */
	  if (TYPE_DOMAIN (type) == 0 ||
	      TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) == NOP_EXPR)
	    return TRUE;

	  /* Check if the string size is greater than SUSPICIOUS_BUF_SIZE */
	  if (TREE_INT_CST_LOW(TYPE_MAX_VALUE(TYPE_DOMAIN(type)))+1 >= SUSPICIOUS_BUF_SIZE)
	    return TRUE;
	}
      return search_string_def(TREE_TYPE(type));
	
    case UNION_TYPE:
    case QUAL_UNION_TYPE:
    case RECORD_TYPE:
      /* Output the name, type, position (in bits), size (in bits) of each
	 field.  */
      for (tem = TYPE_FIELDS (type); tem; tem = TREE_CHAIN (tem))
	{
	  /* Omit here local type decls until we know how to support them. */
	  if ((TREE_CODE (tem) == TYPE_DECL)
	      || (TREE_CODE (tem) == VAR_DECL && TREE_STATIC (tem)))
	    continue;

	  if (search_string_def(TREE_TYPE(tem))) return TRUE;
	}
      break;
	
    case POINTER_TYPE:
    case REFERENCE_TYPE:
      /* I'm not sure whether OFFSET_TYPE needs this treatment,
	 so I'll play safe and return 1.  */
    case OFFSET_TYPE:
    default:
      break;
    }

  return FALSE;
}


static int
search_pointer_def (type)
     tree type;
{
  tree tem;
    
  /* Mark it as defined, so that if it is self-referent
     we will not get into an infinite recursion of definitions.  */

  switch (TREE_CODE (type))
    {
    case UNION_TYPE:
    case QUAL_UNION_TYPE:
    case RECORD_TYPE:
      /* Output the name, type, position (in bits), size (in bits) of each
	 field.  */
      for (tem = TYPE_FIELDS (type); tem; tem = TREE_CHAIN (tem))
	{
	  /* Omit here local type decls until we know how to support them. */
	  if ((TREE_CODE (tem) == TYPE_DECL)
	      || (TREE_CODE (tem) == VAR_DECL && TREE_STATIC (tem)))
	    continue;

	  if (search_pointer_def (TREE_TYPE(tem))) return TRUE;
	}
      break;

    case ARRAY_TYPE:
      return search_pointer_def (TREE_TYPE(type));
	
    case POINTER_TYPE:
    case REFERENCE_TYPE:
      /* I'm not sure whether OFFSET_TYPE needs this treatment,
	 so I'll play safe and return 1.  */
    case OFFSET_TYPE:
      if (TYPE_READONLY (TREE_TYPE (type)))
	{
	  int funcp = search_func_pointer (TREE_TYPE (type), 1);
	  /* Un-mark the type as having been visited already */
	  search_func_pointer (TREE_TYPE (type), 0);
	  return funcp;
	}
      return TRUE;
	
    default:
      break;
    }

  return FALSE;
}


static int
search_func_pointer (type, mark)
     tree type;
     int mark;
{
  tree tem;
    
  /* Mark it as defined, so that if it is self-referent
     we will not get into an infinite recursion of definitions.  */

  switch (TREE_CODE (type))
    {
    case UNION_TYPE:
    case QUAL_UNION_TYPE:
    case RECORD_TYPE:
	if (TREE_ASM_WRITTEN (type) != mark)
	  {
	    /* mark the type as having been visited already */
	    TREE_ASM_WRITTEN (type) = mark;

	    /* Output the name, type, position (in bits), size (in bits) of
	       each field.  */
	    for (tem = TYPE_FIELDS (type); tem; tem = TREE_CHAIN (tem))
	      {
		/* Omit here local type decls until we know how to support them. */
		if (TREE_CODE (tem) == FIELD_DECL
		    && search_func_pointer (TREE_TYPE(tem), mark)) return TRUE;
	      }
	  }
	break;

    case ARRAY_TYPE:
      return search_func_pointer (TREE_TYPE(type), mark);
	
    case POINTER_TYPE:
    case REFERENCE_TYPE:
      /* I'm not sure whether OFFSET_TYPE needs this treatment,
	 so I'll play safe and return 1.  */
    case OFFSET_TYPE:
      return TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE;
	
    default:
      break;
    }

  return FALSE;
}


static void
reset_used_flags_for_insns (insn)
     rtx insn;
{
  register int i, j;
  register enum rtx_code code;
  register const char *format_ptr;

  for (; insn; insn = NEXT_INSN (insn))
    if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN
	|| GET_CODE (insn) == CALL_INSN)
      {
	code = GET_CODE (insn);
	insn->used = 0;
	format_ptr = GET_RTX_FORMAT (code);

	for (i = 0; i < GET_RTX_LENGTH (code); i++)
	  {
	    switch (*format_ptr++) {
	    case 'e':
	      reset_used_flags_of_plus (XEXP (insn, i));
	      break;
			
	    case 'E':
	      for (j = 0; j < XVECLEN (insn, i); j++)
		reset_used_flags_of_plus (XVECEXP (insn, i, j));
	      break;
	    }
	  }
      }
}

static void
reset_used_flags_for_decls (block)
     tree block;
{
  tree types;
  rtx home;

  while (block && TREE_CODE(block)==BLOCK)
    {
      types = BLOCK_VARS(block);
	
      while (types)
	{
	  /* skip the declaration that refers an external variable and
	     also skip an global variable */
	  if (! DECL_EXTERNAL (types))
	    {
	      if (!DECL_RTL_SET_P (types)) goto next;
	      home = DECL_RTL (types);

	      if (GET_CODE (home) == MEM
		  && GET_CODE (XEXP (home, 0)) == PLUS
		  && GET_CODE (XEXP (XEXP (home, 0), 1)) == CONST_INT)
		{
		  XEXP (home, 0)->used = 0;
		}
	    }
	next:
	  types = TREE_CHAIN(types);
	}

      reset_used_flags_for_decls (BLOCK_SUBBLOCKS (block));

      block = BLOCK_CHAIN (block);
    }
}

/* Clear the USED bits only of type PLUS in X */

static void
reset_used_flags_of_plus (x)
     rtx x;
{
  register int i, j;
  register enum rtx_code code;
  register const char *format_ptr;

  if (x == 0)
    return;

  code = GET_CODE (x);

  /* These types may be freely shared so we needn't do any resetting
     for them.  */

  switch (code)
    {
    case REG:
    case QUEUED:
    case CONST_INT:
    case CONST_DOUBLE:
    case SYMBOL_REF:
    case CODE_LABEL:
    case PC:
    case CC0:
      return;

    case INSN:
    case JUMP_INSN:
    case CALL_INSN:
    case NOTE:
    case LABEL_REF:
    case BARRIER:
      /* The chain of insns is not being copied.  */
      return;
      
    case PLUS:
      x->used = 0;
      break;

    case CALL_PLACEHOLDER:
      reset_used_flags_for_insns (XEXP (x, 0));
      reset_used_flags_for_insns (XEXP (x, 1));
      reset_used_flags_for_insns (XEXP (x, 2));
      break;

    default:
      break;
    }

  format_ptr = GET_RTX_FORMAT (code);
  for (i = 0; i < GET_RTX_LENGTH (code); i++)
    {
      switch (*format_ptr++)
	{
	case 'e':
	  reset_used_flags_of_plus (XEXP (x, i));
	  break;

	case 'E':
	  for (j = 0; j < XVECLEN (x, i); j++)
	    reset_used_flags_of_plus (XVECEXP (x, i, j));
	  break;
	}
    }
}


static void
rtl_prologue (insn)
     rtx insn;
{
  for (; insn; insn = NEXT_INSN (insn))
    if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_BEG)
      {
	rtx _val;

	prologue_insert_point = NEXT_INSN (insn);	/* mark the next insn of FUNCTION_BEG insn */
		
	start_sequence ();

	_guard = gen_rtx_MEM (GUARD_m, gen_rtx_SYMBOL_REF (Pmode, "__guard"));
	emit_move_insn ( guard_area, _guard);

	_val = gen_sequence ();
	end_sequence ();

	emit_insn_before (_val, prologue_insert_point);
	break;
      }
}

static void
rtl_epilogue (insn)
     rtx insn;
{
  /* Like STACK_BOUNDARY but in units of bytes, not bits.  */
#define STACK_BYTES (STACK_BOUNDARY / BITS_PER_UNIT)

  rtx if_false_label;
  rtx _val, handler, funcname, addr;
  tree funcstr;
  HOST_WIDE_INT args_size;
  enum machine_mode arg1mode;
		
  handler = gen_rtx_MEM (FUNCTION_MODE, gen_rtx (SYMBOL_REF, Pmode, "__stack_smash_handler"));

  start_sequence ();

  compare_from_rtx (guard_area, _guard, NE, 0, GUARD_m, 0, 0);	/* if (guard_area != _guard) */

  if_false_label = gen_label_rtx ();				/* { */
  emit_jump_insn ( gen_beq(if_false_label));

  /*
    In the function force_const_mem in varasm.c of egcs-1.1.2-30, there is a 
    failure to assign the guard_area variable to eax register, which destroys 
    the return value of the function.

    The BUG preceding comment is an apropriate processes.
    When the bug is fixed, removes the comment
  */

  /* generate string for the current function name */
  funcstr = build_string (strlen(current_function_name)+1, current_function_name);
  TREE_TYPE (funcstr) = build_array_type (char_type_node, 0);/* = char_array_type_node;*/
  funcname = output_constant_def (funcstr, 0);

  addr = gen_push_operand ();
  emit_move_insn (gen_rtx_MEM (GUARD_m, addr), guard_area);		/* push the value of guard area */

  arg1mode = GET_MODE (XEXP (funcname, 0));
  addr = gen_push_operand ();
  emit_move_insn (gen_rtx_MEM (arg1mode, addr), XEXP (funcname, 0));	/* push current_function_name */

  /* calculate the stack size of two arguments */
  args_size = GET_MODE_SIZE (arg1mode) + GET_MODE_SIZE (GUARD_m);
#ifdef PUSH_ROUNDING
  args_size = PUSH_ROUNDING (GET_MODE_SIZE (arg1mode)) + PUSH_ROUNDING (GET_MODE_SIZE (GUARD_m));
#endif
#ifdef STACK_BOUNDARY
  args_size = (((args_size + (STACK_BYTES - 1)) / STACK_BYTES) * STACK_BYTES);
#endif

  /* jump to the stack smash handler */
  emit_call_insn (GEN_CALL (handler, GEN_INT (args_size), const0_rtx, const0_rtx));

  /* generate RTL to return from the current function */
		
  emit_barrier ();						/* } */
  emit_label (if_false_label);

  /* generate RTL to return from the current function */
  if (DECL_RTL_SET_P (DECL_RESULT (current_function_decl)))
    use_return_register ();

  _val = gen_sequence ();
  end_sequence ();

  emit_insn_after (_val, insn);
}


static void
arrange_var_order (block)
     tree block;
{
  tree types;
  int offset;
    
  while (block && TREE_CODE(block)==BLOCK)
    {
      types = BLOCK_VARS (block);

      while (types)
	{
	  /* skip the declaration that refers an external variable */
	  if (! DECL_EXTERNAL (types) && ! TREE_STATIC (types)
	      && TREE_CODE (types) == VAR_DECL
	      && GET_CODE (DECL_RTL (types)) == MEM)
	    {
	      if (search_string_def (TREE_TYPE (types)))
		{
		  /* found a string variable */
		  int var_size =
		    ((TREE_INT_CST_LOW (DECL_SIZE (types)) + BITS_PER_UNIT - 1)
		     / BITS_PER_UNIT);

		  if (GET_MODE (DECL_RTL (types)) == BLKmode)
		    {
		      int alignment = BIGGEST_ALIGNMENT / BITS_PER_UNIT;
		      var_size = CEIL_ROUND (var_size, alignment);
		    }

		  /* skip the variable if it is top of the region
		     specified by sweep_frame_offset */
		  offset = DEBUGGER_AUTO_OFFSET (XEXP (DECL_RTL (types), 0));
		  if (offset >= sweep_frame_offset - var_size)
		    sweep_frame_offset -= var_size;

		  else
		    sweep_string_variable (DECL_RTL (types), var_size);
		}
	    }

	  types = TREE_CHAIN(types);
	}

      arrange_var_order (BLOCK_SUBBLOCKS (block));

      block = BLOCK_CHAIN (block);
    }
}


static void
copy_args_for_protection (void)
{
  tree parms = DECL_ARGUMENTS (current_function_decl);
  rtx temp_rtx;
  int idx;

  escaped_arg_list_size = 0;

  /* count the number of argument passed in memory */
  for (; parms; parms = TREE_CHAIN (parms))
    if (DECL_NAME (parms) && TREE_TYPE (parms) != error_mark_node)
      {
	if (PARM_PASSED_IN_MEMORY (parms))
	  escaped_arg_list_size ++;
      }

  if (escaped_arg_list) free (escaped_arg_list);
  escaped_arg_list = xmalloc (sizeof (arg_status) * escaped_arg_list_size);
  
  parms = DECL_ARGUMENTS (current_function_decl);
  for (idx = 0; parms; parms = TREE_CHAIN (parms), idx++)
    if (DECL_NAME (parms) && TREE_TYPE (parms) != error_mark_node)
      {
	if (PARM_PASSED_IN_MEMORY (parms) && DECL_NAME (parms))
	  {
	    int string_p;

	    /*
	      skip arguemnt protection if the last argument is used
	      for the variable argument
	    */
	    /*
	      tree fntype;
	      if (TREE_CHAIN (parms) == 0)
	      {
	        fntype = TREE_TYPE (current_function_decl);

	        if ((TYPE_ARG_TYPES (fntype) != 0 &&
	             TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype))) != void_type_node)
	             || current_function_varargs)
	          continue;
	      }
	    */

	    escaped_arg_list[idx].original = 0;
	    escaped_arg_list[idx].escaped = 0;
		
	    string_p = search_string_def (TREE_TYPE(parms));

	    /* check if it is a candidate to move */
	    if (string_p || search_pointer_def (TREE_TYPE (parms)))
	      {
		int arg_size
		  = ((TREE_INT_CST_LOW (DECL_SIZE (parms)) + BITS_PER_UNIT - 1)
		     / BITS_PER_UNIT);
		
		start_sequence ();

		if (GET_CODE (DECL_RTL (parms)) == REG)
		  {
		    rtx movinsn;
		    rtx safe = gen_reg_rtx (GET_MODE (DECL_RTL (parms)));

		    /* generate codes for copying the content */
		    movinsn = emit_move_insn (safe, DECL_RTL (parms));
		    PATTERN (movinsn)->volatil = 1;	/* avoid register elimination in gcse.c (COPY-PROP)*/

		    change_arg_use_of_insns (prologue_insert_point, DECL_RTL (parms), safe, 0);

		    /* save debugger info */
		    escaped_arg_list[idx].original = DECL_RTL (parms);
		    escaped_arg_list[idx].escaped = safe;
		  }

		else if (GET_CODE (DECL_RTL (parms)) == MEM
			 && GET_CODE (XEXP (DECL_RTL (parms), 0)) == ADDRESSOF)
		  {
		    rtx movinsn;
		    rtx safe = gen_reg_rtx (GET_MODE (DECL_RTL (parms)));

		    /* generate codes for copying the content */
		    movinsn = emit_move_insn (safe, DECL_INCOMING_RTL (parms));
		    PATTERN (movinsn)->volatil = 1;	/* avoid register elimination in gcse.c (COPY-PROP)*/

		    /* change the addressof information to the newly allocated pseudo register */
		    emit_move_insn (DECL_RTL (parms), safe);

		    /* save debugger info */
		    escaped_arg_list[idx].original = DECL_RTL (parms);
		    escaped_arg_list[idx].escaped = safe;
		  }
			
		else
		  {
		    /* declare temporary local variable DECL_NAME (parms) for it */
		    temp_rtx
		      = assign_stack_local (DECL_MODE (parms), arg_size,
					    DECL_MODE (parms) == BLKmode ? -1 : 0);
		    
		    MEM_IN_STRUCT_P (temp_rtx) = AGGREGATE_TYPE_P (TREE_TYPE (parms));
		    MEM_ALIAS_SET (temp_rtx) = get_alias_set (parms);

		    /* generate codes for copying the content */
		    store_expr (parms, temp_rtx, 0);

		    /* change the reference for each instructions */
		    move_arg_location (prologue_insert_point, DECL_RTL (parms),
				       temp_rtx, arg_size);

		    /* change the location of parms variable */
		    SET_DECL_RTL (parms, temp_rtx);

		    /* change debugger info */
		    DECL_INCOMING_RTL (parms) = temp_rtx;
		  }

		emit_insn_before (gen_sequence (), prologue_insert_point);
		end_sequence ();

#ifndef FRAME_GROWS_DOWNWARD
		/* process the string argument */
		if (string_p && guard_has_legitimate_address)
		  {
		    if (DECL_MODE (parms) == BLKmode)
		      {
			int alignment = BIGGEST_ALIGNMENT / BITS_PER_UNIT;
			arg_size = CEIL_ROUND (arg_size, alignment);
		      }
			
		    /* change the reference for each instructions */
		    sweep_string_variable (DECL_RTL (parms), arg_size);
		  }
#endif
	      }
	  }
      }
}


/*
  sweep a string variable to the local variable addressed by sweep_frame_offset, that is
  a last position of string variables.
*/
static void
sweep_string_variable (sweep_var, var_size)
     int var_size;
     rtx sweep_var;
{
  int sweep_offset = DEBUGGER_AUTO_OFFSET(XEXP (sweep_var, 0));

  /* scan all declarations of variables and fix the offset address of
     the variable based on the frame pointer */
  sweep_string_in_decls (DECL_INITIAL (current_function_decl), sweep_offset, var_size);

  /* scan all argument variable and fix the offset address based on the frame pointer */
  sweep_string_in_args (DECL_ARGUMENTS (current_function_decl), sweep_offset, var_size);

  /* For making room for sweep variable, scan all insns and fix the offset address
     of the variable that is based on frame pointer*/
  sweep_string_use_of_insns (function_first_insn, sweep_offset, var_size);


  /* Clear all the USED bits in operands of all insns and declarations of local vars */
  reset_used_flags_for_decls (DECL_INITIAL (current_function_decl));
  reset_used_flags_for_insns (function_first_insn);

  sweep_frame_offset -= var_size;
}



/*
  move an argument to the local variable addressed by frame_offset
*/
static void
move_arg_location (insn, orig, new, var_size)
     rtx  insn, orig, new;
     int var_size;
{
  /* For making room for sweep variable, scan all insns and fix the offset address
     of the variable that is based on frame pointer*/
  change_arg_use_of_insns (insn, orig, new, var_size);


  /* Clear all the USED bits in operands of all insns and declarations of local vars */
  reset_used_flags_for_insns (insn);
}


static void
sweep_string_in_decls (block, sweep_offset, sweep_size)
     tree block;
     int sweep_offset, sweep_size;
{
  tree types;
  HOST_WIDE_INT offset;
  rtx home;

  while (block && TREE_CODE(block)==BLOCK)
    {
      types = BLOCK_VARS(block);
	
      while (types)
	{
	  /* skip the declaration that refers an external variable and
	     also skip an global variable */
	  if (! DECL_EXTERNAL (types) && ! TREE_STATIC (types)) {
	    
	    if (!DECL_RTL_SET_P (types)) goto next;
	    home = DECL_RTL (types);

	    /* process for static local variable */
	    if (GET_CODE (home) == MEM
		&& GET_CODE (XEXP (home, 0)) == SYMBOL_REF)
	      goto next;

	    if (GET_CODE (home) == MEM
		&& GET_CODE (XEXP (home, 0)) == REG)
	      {
		goto next;
	      }
		
	    if (GET_CODE (home) == MEM
		&& GET_CODE (XEXP (home, 0)) == MEM)
	      {
		/* process for dynamically allocated aray */
		home = XEXP (home, 0);
	      }
		
	    if (GET_CODE (home) == MEM
		&& GET_CODE (XEXP (home, 0)) == PLUS
		&& GET_CODE (XEXP (XEXP (home, 0), 1)) == CONST_INT)
	      {
		if (! XEXP (home, 0)->used)
		  {
		    offset = DEBUGGER_AUTO_OFFSET(XEXP (home, 0));

		    /* the operand related to the sweep variable */
		    if (sweep_offset <= offset
			&& offset < sweep_offset + sweep_size)
		      {

			offset += sweep_frame_offset - sweep_size - sweep_offset;
			XEXP (XEXP (home, 0), 1) = gen_rtx_CONST_INT (VOIDmode, offset);

			/* mark */
			XEXP (home, 0)->used = 1;
		      }
		    else if (sweep_offset <= offset
			     && offset < sweep_frame_offset)
		      {	/* the rest of variables under sweep_frame_offset,
			   so shift the location */

			XEXP (XEXP (home, 0), 1)
			  = gen_rtx_CONST_INT (VOIDmode, offset - sweep_size);

			/* mark */
			XEXP (home, 0)->used = 1;
		      }
		  }
	      }

	  }
	next:
	  types = TREE_CHAIN(types);
	}

      sweep_string_in_decls (BLOCK_SUBBLOCKS (block), sweep_offset, sweep_size);
      block = BLOCK_CHAIN (block);
    }
}


static void
sweep_string_in_args (parms, sweep_offset, sweep_size)
     tree parms;
     int sweep_offset, sweep_size;
{
  rtx home;
  HOST_WIDE_INT offset;
    
  for (; parms; parms = TREE_CHAIN (parms))
    if (DECL_NAME (parms) && TREE_TYPE (parms) != error_mark_node)
      {
	if (PARM_PASSED_IN_MEMORY (parms) && DECL_NAME (parms))
	  {
	    home = DECL_INCOMING_RTL (parms);

	    if (XEXP (home, 0)->used) continue;

	    offset = DEBUGGER_AUTO_OFFSET(XEXP (home, 0));

	    /* the operand related to the sweep variable */
	    if (DEBUGGER_AUTO_BASEPTR (XEXP (home, 0)) == virtual_stack_vars_rtx)
	      {
		if (sweep_offset <= offset
		    && offset < sweep_offset + sweep_size)
		  {
		    offset += sweep_frame_offset - sweep_size - sweep_offset;
		    XEXP (XEXP (home, 0), 1) = gen_rtx_CONST_INT (VOIDmode, offset);

		    /* mark */
		    XEXP (home, 0)->used = 1;
		  }
		else if (sweep_offset <= offset
			 && offset < sweep_frame_offset)
		  {	/* the rest of variables under sweep_frame_offset, so shift the location */
		    XEXP (XEXP (home, 0), 1) = gen_rtx_CONST_INT (VOIDmode, offset - sweep_size);

		    /* mark */
		    XEXP (home, 0)->used = 1;
		  }
	      }
	  }
      }
}


static void
sweep_string_use_of_insns (insn, sweep_offset, sweep_size)
     rtx insn;
     int sweep_offset, sweep_size;
{
  for (; insn; insn = NEXT_INSN (insn))
    if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN
	|| GET_CODE (insn) == CALL_INSN)
      {
	sweep_string_in_operand (PATTERN (insn), sweep_offset, sweep_size);
      }
}


static void
sweep_string_in_operand (orig, sweep_offset, sweep_size)
     rtx orig;
     int sweep_offset, sweep_size;
{
  register rtx x = orig;
  register enum rtx_code code;
  int offset, i, j;
  const char *fmt;

  if (x == 0)
    return;

  code = GET_CODE (x);

  switch (code)
    {
    case CONST_INT:
    case CONST_DOUBLE:
    case CONST:
    case SYMBOL_REF:
    case CODE_LABEL:
    case PC:
    case CC0:
    case ASM_INPUT:
    case ADDR_VEC:
    case ADDR_DIFF_VEC:
    case RETURN:
    case REG:
    case ADDRESSOF:
      return;
	    
    case SET:
      break;
	    
    case PLUS:
      /* Handle special case of frame register plus constant.  */
      if (CONSTANT_P (XEXP (x, 1))
	  && XEXP (x, 0) == virtual_stack_vars_rtx
	  && ! x->used)
	{
	  offset = DEBUGGER_AUTO_OFFSET(x);

	  /* the operand related to the sweep variable */
	  if (sweep_offset <= offset
	      && offset < sweep_offset + sweep_size)
	    {
	      offset += sweep_frame_offset - sweep_size - sweep_offset;

	      XEXP (x, 0) = virtual_stack_vars_rtx;
	      XEXP (x, 1) = gen_rtx_CONST_INT (VOIDmode, offset);
	      x->used = 1;

	      return;
	    }
	  else if (sweep_offset <= offset
		   && offset < sweep_frame_offset)
	    {	/* the rest of variables under sweep_frame_offset, so shift the location */
	      XEXP (x, 1) = gen_rtx_CONST_INT (VOIDmode, offset - sweep_size);
	      x->used = 1;

	      return;
	    }

	  /*
	    process further subtree:
	    Example:  (plus:SI (mem/s:SI (plus:SI (reg:SI 17) (const_int 8)))
	    (const_int 5))
	  */
	}
      break;

    case CALL_PLACEHOLDER:
      sweep_string_use_of_insns (XEXP (x, 0), sweep_offset, sweep_size);
      sweep_string_use_of_insns (XEXP (x, 1), sweep_offset, sweep_size);
      sweep_string_use_of_insns (XEXP (x, 2), sweep_offset, sweep_size);
      break;

    default:
      break;
    }

  /* Scan all subexpressions.  */
  fmt = GET_RTX_FORMAT (code);
  for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++)
    if (*fmt == 'e')
      {
	sweep_string_in_operand (XEXP (x, i), sweep_offset, sweep_size);
      }
    else if (*fmt == 'E')
      for (j = 0; j < XVECLEN (x, i); j++)
	sweep_string_in_operand (XVECEXP (x, i, j), sweep_offset, sweep_size);
}   


/*
  change a argument variable to the local variable addressed by the "new" variable.
*/
static void
change_arg_use_of_insns (insn, orig, new, size)
     rtx insn, orig, new;
     int size;
{
  for (; insn; insn = NEXT_INSN (insn))
    if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN
	|| GET_CODE (insn) == CALL_INSN)
      {
	change_arg_use_in_operand (PATTERN (insn), orig, new, size);
      }
}


static void
change_arg_use_in_operand (x, orig, new, size)
     rtx x, orig, new;
     int size;
{
  register enum rtx_code code;
  int offset, i, j;
  const char *fmt;

  if (x == 0)
    return;

  code = GET_CODE (x);

  switch (code)
    {
    case CONST_INT:
    case CONST_DOUBLE:
    case CONST:
    case SYMBOL_REF:
    case CODE_LABEL:
    case PC:
    case CC0:
    case ASM_INPUT:
    case ADDR_VEC:
    case ADDR_DIFF_VEC:
    case RETURN:
    case REG:
    case ADDRESSOF:
      return;
	    
    case PLUS:
      /* Handle special case of frame register plus constant.  */
      if (GET_CODE (orig) == MEM /* skip if orig is register variable in the optimization */
	  && XEXP (x, 0) == virtual_incoming_args_rtx && CONSTANT_P (XEXP (x, 1))
	  && ! x->used)
	{
	  offset = DEBUGGER_AUTO_OFFSET(x);

	  /* the operand related to the sweep variable */
	  if (DEBUGGER_AUTO_OFFSET(XEXP (orig, 0)) <= offset &&
	      offset < DEBUGGER_AUTO_OFFSET(XEXP (orig, 0)) + size) {

	    offset += frame_offset - DEBUGGER_AUTO_OFFSET(XEXP (orig, 0));

	    XEXP (x, 0) = virtual_stack_vars_rtx;
	    XEXP (x, 1) = gen_rtx_CONST_INT (VOIDmode, offset);
	    x->used = 1;

	    return;
	  }

	  /*
	    process further subtree:
	    Example:  (plus:SI (mem/s:SI (plus:SI (reg:SI 17) (const_int 8)))
	    (const_int 5))
	  */
	}
      break;

    case CALL_PLACEHOLDER:
      change_arg_use_of_insns (XEXP (x, 0), orig, new, size);
      change_arg_use_of_insns (XEXP (x, 1), orig, new, size);
      change_arg_use_of_insns (XEXP (x, 2), orig, new, size);
      break;

    default:
      break;
    }

  /* Scan all subexpressions.  */
  fmt = GET_RTX_FORMAT (code);
  for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++)
    if (*fmt == 'e')
      {
	if (XEXP (x, i) == orig)
	  {
	    XEXP (x, i) = new;
	    continue;
	  }
	change_arg_use_in_operand (XEXP (x, i), orig, new, size);
      }
    else if (*fmt == 'E')
      for (j = 0; j < XVECLEN (x, i); j++)
	{

	  if (XVECEXP (x, i, j) == orig)
	    {
	      XVECEXP (x, i, j) = new;
	      continue;
	    }
	  change_arg_use_in_operand (XVECEXP (x, i, j), orig, new, size);
	}
}   




/*
  The following codes are invoked after the instantiation of pseuso registers.

  Reorder local variables to place a peudo register after buffers to avoid
  the corruption of local variables that could be used to further corrupt
  arbitrary memory locations.
*/
#ifndef FRAME_GROWS_DOWNWARD
static void push_frame PARAMS ((int var_size));
static void push_frame_in_decls PARAMS ((tree block, int push_size));
static void push_frame_in_args PARAMS ((tree parms, int push_size));
static void push_frame_of_insns PARAMS ((rtx insn, int push_size));
static void push_frame_in_operand PARAMS ((rtx orig, int push_size));
static void push_frame_of_reg_equiv_memory_loc PARAMS ((int push_size));
static void push_frame_of_reg_equiv_constant PARAMS ((int push_size));
static void reset_used_flags_for_push_frame PARAMS ((void));
#endif

rtx
assign_stack_local_for_pseudo_reg (mode, size, align)
     enum machine_mode mode;
     HOST_WIDE_INT size;
     int align;
{
#ifdef FRAME_GROWS_DOWNWARD
  return assign_stack_local (mode, size, align);
#else
  tree blocks = DECL_INITIAL (current_function_decl);
  rtx new;
  HOST_WIDE_INT previous_frame_offset, offset;

  previous_frame_offset = frame_offset;
  new = assign_stack_local (mode, size, align);
  if (! flag_propolice_protection
      || size == 0
      || ! blocks
      || DECL_INLINE (current_function_decl)
      || ! search_string_from_argsandvars ()
      || query_trampoline_list())
    return new;

  push_frame (frame_offset - previous_frame_offset);

  /* If we have already instantiated virtual registers, return the actual
     address relative to the frame pointer.  */
/*if (virtuals_instantiated) {*/
    offset = DEBUGGER_AUTO_OFFSET(XEXP (new, 0));

    offset -= previous_frame_offset;
    XEXP (XEXP (new, 0), 1) = gen_rtx_CONST_INT (VOIDmode, offset);
/*}*/
    
  return new;
#endif
}


#ifndef FRAME_GROWS_DOWNWARD
/*
  push frame infomation for instantiating pseudo register at the top of stack.
  This is only for the "frame grows upward", it means FRAME_GROWS_DOWNWARD is 
  not defined.

  It is called by purge_addressof function and global_alloc (or reload)
  function.
*/
static void
push_frame (var_size)
     int var_size;
{
  reset_used_flags_for_push_frame();

  /* scan all declarations of variables and fix the offset address of the variable based on the frame pointer */
  push_frame_in_decls (DECL_INITIAL (current_function_decl), var_size);

  /* scan all argument variable and fix the offset address based on the frame pointer */
  push_frame_in_args (DECL_ARGUMENTS (current_function_decl), var_size);

  /* scan all operands of all insns and fix the offset address based on the frame pointer */
  push_frame_of_insns (get_insns (), var_size);

  /* scan all reg_equiv_memory_loc and reg_equiv_constant*/
  push_frame_of_reg_equiv_memory_loc (var_size);
  push_frame_of_reg_equiv_constant (var_size);

  reset_used_flags_for_push_frame();
}

static void
reset_used_flags_for_push_frame()
{
  int i;
  extern rtx *reg_equiv_memory_loc;
  extern rtx *reg_equiv_constant;

  /* Clear all the USED bits in operands of all insns and declarations of local vars */
  reset_used_flags_for_decls (DECL_INITIAL (current_function_decl));
  reset_used_flags_for_insns (get_insns ());


  /* The following codes are processed if the push_frame is called from 
     global_alloc (or reload) function */
  if (reg_equiv_memory_loc == 0) return;

  for (i=LAST_VIRTUAL_REGISTER+1; i < max_regno; i++)
    if (reg_equiv_memory_loc[i])
      {
	rtx x = reg_equiv_memory_loc[i];

	if (GET_CODE (x) == MEM
	    && GET_CODE (XEXP (x, 0)) == PLUS
	    && DEBUGGER_AUTO_BASEPTR (XEXP (x, 0)) == frame_pointer_rtx)
	  {
	    /* reset */
	    XEXP (x, 0)->used = 0;
	  }
      }

  
  if (reg_equiv_constant == 0) return;

  for (i=LAST_VIRTUAL_REGISTER+1; i < max_regno; i++)
    if (reg_equiv_constant[i])
      {
	rtx x = reg_equiv_constant[i];

	if (GET_CODE (x) == PLUS
	    && DEBUGGER_AUTO_BASEPTR (x) == frame_pointer_rtx)
	  {
	    /* reset */
	    x->used = 0;
	  }
      }
}

static void
push_frame_in_decls (block, push_size)
     tree block;
     int push_size;
{
  tree types;
  HOST_WIDE_INT offset;
  rtx home;

  while (block && TREE_CODE(block)==BLOCK)
    {
      types = BLOCK_VARS(block);
	
      while (types)
	{
	  /* skip the declaration that refers an external variable and
	     also skip an global variable */
	  if (! DECL_EXTERNAL (types) && ! TREE_STATIC (types))
	    {
	    
	      if (!DECL_RTL_SET_P (types)) goto next;
	      home = DECL_RTL (types);

	      /* process for static local variable */
	      if (GET_CODE (home) == MEM
		  && GET_CODE (XEXP (home, 0)) == SYMBOL_REF)
		goto next;

	      if (GET_CODE (home) == MEM
		  && GET_CODE (XEXP (home, 0)) == REG)
		{
		  goto next;
		}
		
	      if (GET_CODE (home) == MEM
		  && GET_CODE (XEXP (home, 0)) == MEM)
		{

		  /* process for dynamically allocated aray */
		  home = XEXP (home, 0);
		}
		
	      if (GET_CODE (home) == MEM
		  && GET_CODE (XEXP (home, 0)) == PLUS
		  && GET_CODE (XEXP (XEXP (home, 0), 1)) == CONST_INT)
		{
		  if (! XEXP (home, 0)->used)
		    {
		      offset = DEBUGGER_AUTO_OFFSET(XEXP (home, 0));

		      offset += push_size;
		      XEXP (XEXP (home, 0), 1) = gen_rtx_CONST_INT (VOIDmode, offset);

		      /* mark */
		      XEXP (home, 0)->used = 1;
		    }
		}

	    }
	next:
	  types = TREE_CHAIN(types);
	}

      push_frame_in_decls (BLOCK_SUBBLOCKS (block), push_size);
      block = BLOCK_CHAIN (block);
    }
}


static void
push_frame_in_args (parms, push_size)
     tree parms;
     int push_size;
{
  rtx home;
  HOST_WIDE_INT offset;
    
  for (; parms; parms = TREE_CHAIN (parms))
    if (DECL_NAME (parms) && TREE_TYPE (parms) != error_mark_node)
      {
	if (PARM_PASSED_IN_MEMORY (parms) && DECL_NAME (parms))
	  {
	    home = DECL_INCOMING_RTL (parms);

	    if (XEXP (home, 0)->used) continue;

	    offset = DEBUGGER_AUTO_OFFSET(XEXP (home, 0));

	    /* the operand related to the sweep variable */
	    if (DEBUGGER_AUTO_BASEPTR (XEXP (home, 0)) == frame_pointer_rtx)
	      {
		offset += push_size;
		XEXP (XEXP (home, 0), 1) = gen_rtx_CONST_INT (VOIDmode, offset);

		/* mark */
		XEXP (home, 0)->used = 1;
	      }
	  }
      }
}


static void
push_frame_of_insns (insn, push_size)
     rtx insn;
     int push_size;
{
  for (; insn; insn = NEXT_INSN (insn))
    if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN
	|| GET_CODE (insn) == CALL_INSN)
      {
	push_frame_in_operand (PATTERN (insn), push_size);

	/* push frame in NOTE */
	push_frame_in_operand (REG_NOTES (insn), push_size);

	/* push frame in CALL EXPR_LIST */
	if (GET_CODE (insn) == CALL_INSN)
	  push_frame_in_operand (CALL_INSN_FUNCTION_USAGE (insn), push_size);
      }
}


static void
push_frame_in_operand (orig, push_size)
     rtx orig;
     int push_size;
{
  register rtx x = orig;
  register enum rtx_code code;
  int offset, i, j;
  const char *fmt;

  if (x == 0)
    return;

  code = GET_CODE (x);

  switch (code)
    {
    case CONST_INT:
    case CONST_DOUBLE:
    case CONST:
    case SYMBOL_REF:
    case CODE_LABEL:
    case PC:
    case CC0:
    case ASM_INPUT:
    case ADDR_VEC:
    case ADDR_DIFF_VEC:
    case RETURN:
    case REG:
    case ADDRESSOF:
      return;
	    
    case SET:
      break;
	    
    case PLUS:
      /* Handle special case of frame register plus constant.  */
      if (CONSTANT_P (XEXP (x, 1))
	  && XEXP (x, 0) == frame_pointer_rtx
	  && ! x->used)
	{
	  offset = DEBUGGER_AUTO_OFFSET(x);

	  offset += push_size;

	  /* XEXP (x, 0) is frame_pointer_rtx */
	  XEXP (x, 1) = gen_rtx_CONST_INT (VOIDmode, offset);
	  x->used = 1;

	  return;
	}
      /*
	process further subtree:
	Example:  (plus:SI (mem/s:SI (plus:SI (reg:SI 17) (const_int 8)))
	(const_int 5))
      */
      break;

    case CALL_PLACEHOLDER:
      push_frame_of_insns (XEXP (x, 0), push_size);
      push_frame_of_insns (XEXP (x, 1), push_size);
      push_frame_of_insns (XEXP (x, 2), push_size);
      break;

    default:
      break;
    }

  /* Scan all subexpressions.  */
  fmt = GET_RTX_FORMAT (code);
  for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++)
    if (*fmt == 'e')
      {
	push_frame_in_operand (XEXP (x, i), push_size);
      }
    else if (*fmt == 'E')
      for (j = 0; j < XVECLEN (x, i); j++)
	push_frame_in_operand (XVECEXP (x, i, j), push_size);
}   

static void
push_frame_of_reg_equiv_memory_loc (push_size)
     int push_size;
{
  int i;
  extern rtx *reg_equiv_memory_loc;

  /* This function is processed if the push_frame is called from 
     global_alloc (or reload) function */
  if (reg_equiv_memory_loc == 0) return;

  for (i=LAST_VIRTUAL_REGISTER+1; i < max_regno; i++)
    if (reg_equiv_memory_loc[i])
      {
	rtx x = reg_equiv_memory_loc[i];
	int offset;

	if (GET_CODE (x) == MEM
	    && GET_CODE (XEXP (x, 0)) == PLUS
	    && XEXP (XEXP (x, 0), 0) == frame_pointer_rtx)
	  {
	    if (! XEXP (x, 0)->used)
	      {
		offset = DEBUGGER_AUTO_OFFSET(XEXP (x, 0));

		offset += push_size;
		XEXP (XEXP (x, 0), 1) = gen_rtx_CONST_INT (VOIDmode, offset);

		/* mark */
		XEXP (x, 0)->used = 1;
	      }
	  }
      }
}

static void
push_frame_of_reg_equiv_constant (push_size)
     int push_size;
{
  int i;
  extern rtx *reg_equiv_constant;

  /* This function is processed if the push_frame is called from 
     global_alloc (or reload) function */
  if (reg_equiv_constant == 0) return;

  for (i=LAST_VIRTUAL_REGISTER+1; i < max_regno; i++)
    if (reg_equiv_constant[i])
      {
	rtx x = reg_equiv_constant[i];
	int offset;

	if (GET_CODE (x) == PLUS
	    && XEXP (x, 0) == frame_pointer_rtx)
	  {
	    if (! x->used)
	      {
		offset = DEBUGGER_AUTO_OFFSET(x);

		offset += push_size;
		XEXP (x, 1) = gen_rtx_CONST_INT (VOIDmode, offset);

		/* mark */
		x->used = 1;
	      }
	  }
      }
}
#endif


void
set_debuginfo_of_escaped_arg (rtx new, rtx old)
{
  int idx;

  if (flag_propolice_protection)
    for (idx = 0; idx < escaped_arg_list_size; idx++)
      if (escaped_arg_list[idx].original == old)
	{
	  /* change debugger info */
	  escaped_arg_list[idx].escaped = new;
	}
}


void
update_debuginfo_using_escaped_arg_list (tree parms)
{
  rtx orig = DECL_RTL (parms);
  int idx;

  if (flag_propolice_protection && PARM_PASSED_IN_MEMORY (parms))
    for (idx = 0; idx < escaped_arg_list_size; idx++)
      if (escaped_arg_list[idx].original == orig)
	{
	  rtx escaped = escaped_arg_list[idx].escaped;

	  /* skip in the case where the escaped register was deleted */
	  if (GET_CODE (escaped) == REG
	      && REGNO (escaped) >= FIRST_PSEUDO_REGISTER)
	    break;

	  DECL_INCOMING_RTL (parms) = escaped;
	  break;
	}
}
/* Top level of GNU C compiler
   Copyright (C) 1987, 88, 89, 92-7, 1998 Free Software Foundation, Inc.

This file is part of GNU CC.

GNU CC 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 2, or (at your option)
any later version.

GNU CC 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 GNU CC; see the file COPYING.  If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.  */


/* declaration of GUARD variable */
#define GUARD_m		SImode
#define UNITS_PER_GUARD GET_MODE_SIZE (GUARD_m)


#ifndef L_stack_smash_handler

/* insert a guard variable before a character buffer and change the order
 of pointer variables, character buffers and pointer arguments */

extern void prepare_stack_protection  PARAMS ((void));

/* allocate a local variable in the stack area before character buffers
   to avoid the corruption of it */

extern rtx assign_stack_local_for_pseudo_reg PARAMS ((enum machine_mode, HOST_WIDE_INT, int));

/* Update the debug information of the function argument pointed by 'old' */
extern void set_debuginfo_of_escaped_arg PARAMS ((rtx new, rtx old));


/* Nonzero means use propolice as a stack protection method */
extern int flag_propolice_protection;

#endif

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]