This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: gcc stack-smashing protector (for gcc-ss-20001101)
- To: gcc-patches at gcc dot gnu dot org
- Subject: Re: gcc stack-smashing protector (for gcc-ss-20001101)
- From: Hiroaki Etoh <etoh at trl dot ibm dot co dot jp>
- Date: Fri, 03 Nov 2000 10:37:41 +0900
- References: <20001024184333Z.etoh@trl.ibm.com>
This patch introduces -fstack-protector option, which is a stack-smashing
protection mechanism to the latest snapshot (gcc-ss-20001101).
This patch and new files (protector.h and protector.c) are bootstraped
and tested on i686-pc-linux-gnu and powerpc-ibm-aix4.4.0.
Please see the web page
(http://www.trl.ibm.co.jp/projects/security/propolice/) for details and
what is a stack-smashing protection.
Hiroaki Etoh, Tokyo Research Laboratory, IBM Japan
2000-11-02 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: /cvs/gcc/egcs/gcc/Makefile.in,v
retrieving revision 1.532
diff -c -r1.532 Makefile.in
*** Makefile.in 2000/10/28 17:59:04 1.532
--- Makefile.in 2000/11/02 12:56:34
***************
*** 734,740 ****
profile.o insn-attrtab.o $(out_object_file) $(EXTRA_OBJS) convert.o \
mbchar.o splay-tree.o graph.o sbitmap.o resource.o hash.o predict.o \
lists.o ggc-common.o $(GGC) simplify-rtx.o ssa.o bb-reorder.o \
! sibcall.o conflict.o timevar.o ifcvt.o dependence.o dce.o
BACKEND = toplev.o libbackend.a
--- 734,740 ----
profile.o insn-attrtab.o $(out_object_file) $(EXTRA_OBJS) convert.o \
mbchar.o splay-tree.o graph.o sbitmap.o resource.o hash.o predict.o \
lists.o ggc-common.o $(GGC) simplify-rtx.o ssa.o bb-reorder.o \
! sibcall.o conflict.o timevar.o ifcvt.o dependence.o dce.o protector.o
BACKEND = toplev.o libbackend.a
***************
*** 783,789 ****
_bb _shtab _clear_cache _trampoline __main _exit \
_absvsi2 _absvdi2 _addvsi3 _addvdi3 _subvsi3 _subvdi3 \
_mulvsi3 _mulvdi3 _negvsi2 _negvdi2 \
! _ctors
LIB2FUNCS_EH = _eh
--- 783,789 ----
_bb _shtab _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: /cvs/gcc/egcs/gcc/builtins.c,v
retrieving revision 1.62
diff -c -r1.62 builtins.c
*** builtins.c 2000/11/01 03:22:21 1.62
--- builtins.c 2000/11/02 12:56:36
***************
*** 40,45 ****
--- 40,46 ----
#include "defaults.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))
***************
*** 552,558 ****
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
--- 553,559 ----
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: /cvs/gcc/egcs/gcc/cse.c,v
retrieving revision 1.163
diff -c -r1.163 cse.c
*** cse.c 2000/10/26 00:17:53 1.163
--- cse.c 2000/11/02 12:56:41
***************
*** 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
***************
*** 4748,4753 ****
--- 4749,4757 ----
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
***************
*** 6235,6240 ****
--- 6239,6248 ----
rtx dest = SET_DEST (sets[0].rtl);
rtx src = SET_SRC (sets[0].rtl);
rtx note = find_reg_note (prev, REG_EQUIV, NULL_RTX);
+
+ /* 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: /cvs/gcc/egcs/gcc/dbxout.c,v
retrieving revision 1.66
diff -c -r1.66 dbxout.c
*** dbxout.c 2000/10/10 00:13:09 1.66
--- dbxout.c 2000/11/02 12:56:42
***************
*** 2302,2307 ****
--- 2302,2310 ----
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: /cvs/gcc/egcs/gcc/expr.c,v
retrieving revision 1.274
diff -c -r1.274 expr.c
*** expr.c 2000/10/31 16:02:44 1.274
--- expr.c 2000/11/02 12:56:49
***************
*** 44,49 ****
--- 44,50 ----
#include "ggc.h"
#include "intl.h"
#include "tm_p.h"
+ #include "protector.h"
#ifndef ACCUMULATE_OUTGOING_ARGS
#define ACCUMULATE_OUTGOING_ARGS 0
***************
*** 6513,6519 ****
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
--- 6514,6520 ----
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: /cvs/gcc/egcs/gcc/function.c,v
retrieving revision 1.227
diff -c -r1.227 function.c
*** function.c 2000/10/20 18:49:24 1.227
--- function.c 2000/11/02 12:56:53
***************
*** 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
***************
*** 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.
***************
*** 220,225 ****
--- 225,232 ----
/* 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
***************
*** 658,663 ****
--- 665,671 ----
int align;
HOST_WIDE_INT alias_set;
struct temp_slot *p, *best_p = 0;
+ int char_array = type && (TREE_TYPE (type)==char_type_node);
/* If SIZE is -1 it means that somebody tried to allocate a temporary
of a variable size. */
***************
*** 692,698 ****
&& (! flag_strict_aliasing
|| (alias_set && p->alias_set == alias_set))
&& (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)
{
--- 700,707 ----
&& (! flag_strict_aliasing
|| (alias_set && p->alias_set == alias_set))
&& (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)
{
***************
*** 727,732 ****
--- 736,742 ----
p->address = 0;
p->rtl_expr = 0;
p->alias_set = best_p->alias_set;
+ p->boundary_mark = best_p->boundary_mark;
p->next = temp_slots;
temp_slots = p;
***************
*** 788,793 ****
--- 798,804 ----
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;
}
***************
*** 922,935 ****
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;
--- 933,948 ----
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;
***************
*** 1481,1487 ****
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);
--- 1494,1502 ----
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);
***************
*** 7375,7380 ****
--- 7390,7401 ----
}
}
#endif /* HAVE_prologue or HAVE_epilogue */
+ }
+
+ tree
+ query_trampoline_list()
+ {
+ return trampoline_list;
}
/* Mark T for GC. */
Index: gcc/function.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/function.h,v
retrieving revision 1.57
diff -c -r1.57 function.h
*** function.h 2000/10/13 06:26:26 1.57
--- function.h 2000/11/02 12:56:53
***************
*** 600,605 ****
--- 600,608 ----
/* 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: /cvs/gcc/egcs/gcc/gcse.c,v
retrieving revision 1.108
diff -c -r1.108 gcse.c
*** gcse.c 2000/10/24 22:49:39 1.108
--- gcse.c 2000/11/02 12:56:56
***************
*** 3894,3900 ****
/* 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;
--- 3894,3900 ----
/* 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: /cvs/gcc/egcs/gcc/integrate.c,v
retrieving revision 1.119
diff -c -r1.119 integrate.c
*** integrate.c 2000/10/29 09:14:22 1.119
--- integrate.c 2000/11/02 12:56:58
***************
*** 40,45 ****
--- 40,46 ----
#include "toplev.h"
#include "intl.h"
#include "loop.h"
+ #include "protector.h"
#include "obstack.h"
#define obstack_chunk_alloc xmalloc
***************
*** 735,744 ****
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;
--- 736,745 ----
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/libgcc2.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/libgcc2.c,v
retrieving revision 1.106
diff -c -r1.106 libgcc2.c
*** libgcc2.c 2000/11/01 00:43:16 1.106
--- libgcc2.c 2000/11/02 12:56:59
***************
*** 4337,4339 ****
--- 4337,4369 ----
#endif /* IA64_UNWIND_INFO */
#endif /* L_eh */
+
+ #ifdef L_stack_smash_handler
+ #include <fcntl.h>
+ char __guard[32] = "";
+ 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)
+ {
+ char *message = ": stack smashing attack? " ;
+ volatile char *faultloc;
+ write (STDERR_FILENO, func, strlen(func));
+ write (STDERR_FILENO, message, strlen(message));
+ faultloc = 0; *faultloc = *faultloc;
+ exit (666) ;
+ }
+ #endif
+
Index: gcc/reload1.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/reload1.c,v
retrieving revision 1.234
diff -c -r1.234 reload1.c
*** reload1.c 2000/10/28 19:36:04 1.234
--- reload1.c 2000/11/02 12:57:05
***************
*** 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
***************
*** 1900,1906 ****
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.
--- 1901,1907 ----
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: /cvs/gcc/egcs/gcc/toplev.c,v
retrieving revision 1.393
diff -c -r1.393 toplev.c
*** toplev.c 2000/10/31 10:09:34 1.393
--- toplev.c 2000/11/02 12:57:08
***************
*** 903,908 ****
--- 903,915 ----
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
{
***************
*** 1151,1156 ****
--- 1158,1167 ----
"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. */
***************
*** 2778,2783 ****
--- 2789,2796 ----
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))
*** /dev/null Wed May 6 05:32:27 1998
--- protector.h Tue Oct 31 11:32:25 2000
***************
*** 0 ****
--- 1,46 ----
+ /* 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
*** /dev/null Wed May 6 05:32:27 1998
--- protector.c Wed Nov 1 14:36:13 2000
***************
*** 0 ****
--- 1,1722 ----
+ /* 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 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;
+
+
+ #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)
+ {
+ /* 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)
+ {
+ 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))
+ {
+
+ 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)
+ {
+ /* 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)
+ {
+ types = BLOCK_VARS(block);
+
+ while (types)
+ {
+ /* skip the declaration that refers an external variable and
+ also skip an global variable */
+ if (! DECL_EXTERNAL (types))
+ {
+ home = DECL_RTL (types);
+ if (home == 0) goto next;
+
+ 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;
+ rtx return_reg = DECL_RTL (DECL_RESULT (current_function_decl));
+
+ 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);
+
+ 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 (return_reg)
+ 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)
+ {
+ 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))
+ {
+ 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 */
+ 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)
+ {
+ 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)
+ {
+ 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)) {
+
+ home = DECL_RTL (types);
+ if (home == 0) goto next;
+
+ /* 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)
+ {
+ 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))
+ {
+
+ home = DECL_RTL (types);
+ if (home == 0) goto next;
+
+ /* 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;
+ }
+ }