diff -cr /home/etoh/Stack/egcs-1.1.2/gcc/Makefile.in egcs-1.1.2/gcc/Makefile.in *** /home/etoh/Stack/egcs-1.1.2/gcc/Makefile.in Mon Mar 8 09:22:20 1999 --- egcs-1.1.2/gcc/Makefile.in Fri Jun 23 16:11:30 2000 *************** *** 648,654 **** insn-peep.o reorg.o $(SCHED_PREFIX)sched.o final.o recog.o reg-stack.o \ insn-opinit.o insn-recog.o insn-extract.o insn-output.o insn-emit.o \ profile.o insn-attrtab.o $(out_object_file) getpwd.o $(EXTRA_OBJS) convert.o \ ! dyn-string.o # GEN files are listed separately, so they can be built before doing parallel # makes for cc1 or cc1plus. Otherwise sequent parallel make attempts to load --- 648,654 ---- insn-peep.o reorg.o $(SCHED_PREFIX)sched.o final.o recog.o reg-stack.o \ insn-opinit.o insn-recog.o insn-extract.o insn-output.o insn-emit.o \ profile.o insn-attrtab.o $(out_object_file) getpwd.o $(EXTRA_OBJS) convert.o \ ! dyn-string.o protector.o # GEN files are listed separately, so they can be built before doing parallel # makes for cc1 or cc1plus. Otherwise sequent parallel make attempts to load *************** *** 699,705 **** _fixtfdi _fixunstfdi _floatditf \ __gcc_bcmp _varargs __dummy _eprintf \ _bb _shtab _clear_cache _trampoline __main _exit \ ! _ctors _pure LIB2FUNCS_EH = _eh --- 699,705 ---- _fixtfdi _fixunstfdi _floatditf \ __gcc_bcmp _varargs __dummy _eprintf \ _bb _shtab _clear_cache _trampoline __main _exit \ ! _ctors _pure _stack_smash_handler LIB2FUNCS_EH = _eh *************** *** 1092,1098 **** if [ $${name}.asm = $${file} ]; then \ cp $${file} $${name}.s || exit 1; file=$${name}.s; \ else true; fi; \ ! $(GCC_FOR_TARGET) $(LIBGCC2_CFLAGS) $(INCLUDES) -c $${file}; \ if [ $$? -eq 0 ] ; then true; else exit 1; fi; \ $(AR) $(AR_FLAGS) tmplibgcc2.a $${oname}$(objext); \ rm -f $${name}.s $${oname}$(objext); \ --- 1092,1098 ---- if [ $${name}.asm = $${file} ]; then \ cp $${file} $${name}.s || exit 1; file=$${name}.s; \ else true; fi; \ ! $(GCC_FOR_TARGET) -fno-stack-protector $(LIBGCC2_CFLAGS) $(INCLUDES) -c $${file}; \ if [ $$? -eq 0 ] ; then true; else exit 1; fi; \ $(AR) $(AR_FLAGS) tmplibgcc2.a $${oname}$(objext); \ rm -f $${name}.s $${oname}$(objext); \ *************** *** 1379,1385 **** dwarf2out.h sdbout.h dbxout.h \ $(lang_options_files) $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $(MAYBE_USE_COLLECT2) \ ! -DTARGET_NAME=\"$(target_alias)\" \ -c `echo $(srcdir)/toplev.c | sed 's,^\./,,'` rtl.o : rtl.c $(CONFIG_H) system.h $(RTL_H) bitmap.h --- 1379,1385 ---- dwarf2out.h sdbout.h dbxout.h \ $(lang_options_files) $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $(MAYBE_USE_COLLECT2) \ ! -DSTACK_PROTECTOR -DTARGET_NAME=\"$(target_alias)\" \ -c `echo $(srcdir)/toplev.c | sed 's,^\./,,'` rtl.o : rtl.c $(CONFIG_H) system.h $(RTL_H) bitmap.h diff -cr /home/etoh/Stack/egcs-1.1.2/gcc/libgcc2.c egcs-1.1.2/gcc/libgcc2.c *** /home/etoh/Stack/egcs-1.1.2/gcc/libgcc2.c Tue Nov 24 05:37:20 1998 --- egcs-1.1.2/gcc/libgcc2.c Fri Oct 22 12:12:43 1999 *************** *** 3798,3800 **** --- 3798,3873 ---- _exit (-1); } #endif + + #ifdef L_stack_smash_handler + #define HAVE_SYSLOG + #include + #include + #include + + #if defined(HAVE_SYSLOG) + #include + #include + #include + + #if defined(HAVE_SYSLOG) + #include + #endif + #ifndef _PATH_LOG + #define _PATH_LOG "/dev/log" + #endif + #endif + + long __guard = 0; + static void __guard_setup () __attribute__ ((constructor)) ; + static void __guard_setup (void) + { + int fd; + if (__guard!=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\n\777'; + } + void __stack_smash_handler (int damaged, char func[]) + { + #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 + diff -cr /home/etoh/Stack/egcs-1.1.2/gcc/reload1.c egcs-1.1.2/gcc/reload1.c *** /home/etoh/Stack/egcs-1.1.2/gcc/reload1.c Sun Feb 28 03:33:02 1999 --- egcs-1.1.2/gcc/reload1.c Sun Oct 1 14:16:52 2000 *************** *** 2509,2516 **** inherent space, and no less total space, then the previous slot. */ 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. --- 2509,2517 ---- inherent space, and no less total space, then the previous slot. */ if (from_reg == -1) { + extern rtx assign_stack_local_for_pseudo_reg PROTO((enum machine_mode, HOST_WIDE_INT, int)); /* 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. diff -cr /home/etoh/Stack/egcs-1.1.2/gcc/toplev.c egcs-1.1.2/gcc/toplev.c *** /home/etoh/Stack/egcs-1.1.2/gcc/toplev.c Sun Feb 28 03:33:02 1999 --- egcs-1.1.2/gcc/toplev.c Fri Jun 23 16:20:17 2000 *************** *** 726,731 **** --- 726,738 ---- if alias analysis (in general) is enabled. */ int flag_strict_aliasing = 0; + #ifdef STACK_PROTECTOR + /* Nonzero means use ProPolice as a stack protection method */ + int flag_propolice_protection = 1; + #else + int flag_propolice_protection = 0; + #endif + extern int flag_dump_unnumbered; *************** *** 916,921 **** --- 923,935 ---- {"prefix-function-name", &flag_prefix_function_name, 1, "Add a prefix to all function names" }, {"dump-unnumbered", &flag_dump_unnumbered, 1} + #ifdef STACK_PROTECTOR + ,{"no-stack-protector", &flag_propolice_protection, 0, + "Disables stack protection" } + #else + ,{"stack-protector", &flag_propolice_protection, 1, + "Enables stack protection" } + #endif }; #define NUM_ELEM(a) (sizeof (a) / sizeof ((a)[0])) *************** *** 3246,3251 **** --- 3260,3267 ---- insns = get_insns (); + if (flag_propolice_protection) prepare_stack_protection (); + /* Dump the rtl code if we are dumping rtl. */ if (rtl_dump) diff -cr /home/etoh/Stack/egcs-1.1.2/gcc/tree.h egcs-1.1.2/gcc/tree.h *** /home/etoh/Stack/egcs-1.1.2/gcc/tree.h Tue Jul 14 07:29:02 1998 --- egcs-1.1.2/gcc/tree.h Tue Oct 26 11:03:58 1999 *************** *** 2290,2292 **** --- 2290,2302 ---- code for a function definition. */ extern void dwarf2out_end_epilogue PROTO((void)); + + #ifdef STACK_PROTECTOR + /* In protector.c */ + + /* Nonzero if function being compiled can define string buffers that may be + damaged by the stack-smash attack */ + extern int current_function_defines_vulnerable_string; + + extern void prepare_stack_protection PROTO((void)); + #endif diff -cr /home/etoh/Stack/egcs-1.1.2/gcc/gcse.c egcs-1.1.2/gcc/gcse.c *** /home/etoh/Stack/egcs-1.1.2/gcc/gcse.c Mon Mar 8 09:22:20 1999 --- egcs-1.1.2/gcc/gcse.c Mon May 29 17:38:10 2000 *************** *** 3726,3732 **** /* 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; --- 3726,3732 ---- /* 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; diff -cr /home/etoh/Stack/egcs-1.1.2/gcc/cse.c egcs-1.1.2/gcc/cse.c *** /home/etoh/Stack/egcs-1.1.2/gcc/cse.c Mon Mar 8 09:22:20 1999 --- egcs-1.1.2/gcc/cse.c Mon May 29 17:38:10 2000 *************** *** 6214,6219 **** --- 6214,6220 ---- if (SET_DEST (x) == pc_rtx && GET_CODE (SET_SRC (x)) == LABEL_REF) ; + else if (x->volatil) ; /* Don't count call-insns, (set (reg 0) (call ...)), as a set. The hard function value register is used only once, to copy to diff -cr /home/etoh/Stack/egcs-1.1.2/gcc/stmt.c egcs-1.1.2/gcc/stmt.c *** /home/etoh/Stack/egcs-1.1.2/gcc/stmt.c Thu Sep 7 19:08:11 2000 --- egcs-1.1.2/gcc/stmt.c Thu Sep 7 19:13:28 2000 *************** *** 3263,3274 **** oldaddr = XEXP (DECL_RTL (decl), 0); } ! DECL_RTL (decl) ! = assign_stack_temp (DECL_MODE (decl), ! ((TREE_INT_CST_LOW (DECL_SIZE (decl)) ! + BITS_PER_UNIT - 1) ! / BITS_PER_UNIT), ! 1); MEM_IN_STRUCT_P (DECL_RTL (decl)) = AGGREGATE_TYPE_P (TREE_TYPE (decl)); /* Set alignment we actually gave this decl. */ --- 3263,3285 ---- oldaddr = XEXP (DECL_RTL (decl), 0); } ! if (TREE_TYPE (TREE_TYPE (decl)) == char_type_node) /* for ProPolice */ ! { ! extern rtx assign_stack_temp_char_array PROTO((enum machine_mode, HOST_WIDE_INT, int, int)); ! DECL_RTL (decl) ! = assign_stack_temp_char_array (DECL_MODE (decl), ! ((TREE_INT_CST_LOW (DECL_SIZE (decl)) ! + BITS_PER_UNIT - 1) ! / BITS_PER_UNIT), ! 1, 1); ! } ! else ! DECL_RTL (decl) ! = assign_stack_temp (DECL_MODE (decl), ! ((TREE_INT_CST_LOW (DECL_SIZE (decl)) ! + BITS_PER_UNIT - 1) ! / BITS_PER_UNIT), ! 1); MEM_IN_STRUCT_P (DECL_RTL (decl)) = AGGREGATE_TYPE_P (TREE_TYPE (decl)); /* Set alignment we actually gave this decl. */ diff -cr /home/etoh/Stack/egcs-1.1.2/gcc/function.c egcs-1.1.2/gcc/function.c *** /home/etoh/Stack/egcs-1.1.2/gcc/function.c Wed Aug 9 15:22:53 2000 --- egcs-1.1.2/gcc/function.c Wed Aug 9 15:25:00 2000 *************** *** 381,386 **** --- 381,388 ---- /* 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; }; /* List of all temporaries allocated, both available and in use. */ *************** *** 400,405 **** --- 402,412 ---- until no longer needed. CLEANUP_POINT_EXPRs define the lifetime of TARGET_EXPRs. */ int target_temp_slot_level; + + /* Current boundary mark for character arrays. */ + + int temp_boundary_mark; + /* This structure is used to record MEMs or pseudos used to replace VAR, any SUBREGs of VAR, and any MEMs containing VAR as an address. We need to *************** *** 454,459 **** --- 461,469 ---- #endif /* HAVE_prologue || HAVE_epilogue */ static void put_addressof_into_stack PROTO((rtx)); static void purge_addressof_1 PROTO((rtx *, rtx, int)); + + extern rtx assign_stack_local_for_pseudo_reg PROTO ((enum machine_mode, HOST_WIDE_INT, int)); + /* Pointer to chain of `struct function' for containing functions. */ struct function *outer_function_chain; *************** *** 819,824 **** --- 829,835 ---- whose lifetime is controlled by CLEANUP_POINT_EXPRs. KEEP is 3 if we are to allocate something at an inner level to be treated as a variable in the block (e.g., a SAVE_EXPR). */ + rtx assign_stack_temp_char_array PROTO((enum machine_mode, HOST_WIDE_INT, int, int)); rtx assign_stack_temp (mode, size, keep) *************** *** 826,831 **** --- 837,852 ---- HOST_WIDE_INT size; int keep; { + assign_stack_temp_char_array (mode, size, keep, 0); + } + + rtx + assign_stack_temp_char_array (mode, size, keep, char_array) + enum machine_mode mode; + HOST_WIDE_INT size; + int keep; + int char_array; + { struct temp_slot *p, *best_p = 0; /* If SIZE is -1 it means that somebody tried to allocate a temporary *************** *** 836,842 **** /* First try to find an available, already-allocated temporary that is the exact size we require. */ for (p = temp_slots; p; p = p->next) ! if (p->size == size && GET_MODE (p->slot) == mode && ! p->in_use) break; /* If we didn't find, one, try one that is larger than what we want. We --- 857,864 ---- /* First try to find an available, already-allocated temporary that is the exact size we require. */ for (p = temp_slots; p; p = p->next) ! if (p->size == size && GET_MODE (p->slot) == mode && ! p->in_use ! && (! char_array || ! p->boundary_mark)) break; /* If we didn't find, one, try one that is larger than what we want. We *************** *** 844,849 **** --- 866,872 ---- if (p == 0) for (p = temp_slots; p; p = p->next) if (p->size > size && GET_MODE (p->slot) == mode && ! p->in_use + && (! char_array || p->boundary_mark > 0) && (best_p == 0 || best_p->size > p->size)) best_p = p; *************** *** 870,875 **** --- 893,899 ---- rounded_size)); p->address = 0; p->rtl_expr = 0; + p->boundary_mark = best_p->boundary_mark; p->next = temp_slots; temp_slots = p; *************** *** 917,922 **** --- 941,947 ---- 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; } *************** *** 1022,1035 **** 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; --- 1047,1062 ---- 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; *************** *** 1524,1530 **** if (regno < max_parm_reg) new = parm_reg_stack_loc[regno]; if (new == 0) ! new = assign_stack_local (decl_mode, GET_MODE_SIZE (decl_mode), 0); } PUT_MODE (reg, decl_mode); --- 1551,1557 ---- if (regno < max_parm_reg) new = parm_reg_stack_loc[regno]; if (new == 0) ! new = assign_stack_local_for_pseudo_reg (decl_mode, GET_MODE_SIZE (decl_mode), 0); } PUT_MODE (reg, decl_mode); *************** *** 6218,6221 **** --- 6245,6254 ---- } } #endif /* HAVE_prologue or HAVE_epilogue */ + } + + tree + query_trampoline_list() + { + return trampoline_list; } diff -cr /home/etoh/Stack/egcs-1.1.2/gcc/integrate.c egcs-1.1.2/gcc/integrate.c *** /home/etoh/Stack/egcs-1.1.2/gcc/integrate.c Mon Aug 14 18:01:45 2000 --- egcs-1.1.2/gcc/integrate.c Mon Aug 14 18:24:16 2000 *************** *** 1425,1440 **** } else if (GET_CODE (loc) != MEM) { if (GET_MODE (loc) != TYPE_MODE (TREE_TYPE (arg))) /* The mode if LOC and ARG can differ if LOC was a variable that had its mode promoted via PROMOTED_MODE. */ 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; --- 1425,1441 ---- } else if (GET_CODE (loc) != MEM) { + extern int flag_propolice_protection; /* Nonzero means use ProPolice as a stack protection method */ if (GET_MODE (loc) != TYPE_MODE (TREE_TYPE (arg))) /* The mode if LOC and ARG can differ if LOC was a variable that had its mode promoted via PROMOTED_MODE. */ 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; diff -cr /home/etoh/Stack/egcs-1.1.2/gcc/expr.c egcs-1.1.2/gcc/expr.c *** /home/etoh/Stack/egcs-1.1.2/gcc/expr.c Mon Aug 14 18:01:45 2000 --- egcs-1.1.2/gcc/expr.c Fri Sep 1 16:12:22 2000 *************** *** 5978,5984 **** && modifier != EXPAND_MEMORY_USE_WO) return GEN_INT (TREE_STRING_POINTER (string)[i]); ! op0 = expand_expr (exp1, NULL_RTX, VOIDmode, EXPAND_SUM); op0 = memory_address (mode, op0); if (flag_check_memory_usage && !AGGREGATE_TYPE_P (TREE_TYPE (exp))) --- 5978,5984 ---- && modifier != EXPAND_MEMORY_USE_WO) return GEN_INT (TREE_STRING_POINTER (string)[i]); ! op0 = expand_expr (exp1, NULL_RTX, VOIDmode, ro_modifier); op0 = memory_address (mode, op0); if (flag_check_memory_usage && !AGGREGATE_TYPE_P (TREE_TYPE (exp))) *************** *** 8387,8397 **** { rtx mem; int is_aggregate; mem = gen_rtx_MEM (BLKmode, memory_address (BLKmode, expand_expr (exp, NULL_RTX, ! ptr_mode, EXPAND_SUM))); RTX_UNCHANGING_P (mem) = TREE_READONLY (exp); --- 8387,8398 ---- { rtx mem; int is_aggregate; + extern int flag_propolice_protection; /* Nonzero means use ProPolice as a stack protection method */ mem = gen_rtx_MEM (BLKmode, memory_address (BLKmode, expand_expr (exp, NULL_RTX, ! ptr_mode, flag_propolice_protection?EXPAND_NORMAL:EXPAND_SUM))); RTX_UNCHANGING_P (mem) = TREE_READONLY (exp); diff -c /dev/null egcs-1.1.2/gcc/protector.c *** /dev/null Wed May 6 05:32:27 1998 --- egcs-1.1.2/gcc/protector.c Mon Oct 2 20:32:31 2000 *************** *** 0 **** --- 1,1782 ---- + /* 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 "regs.h" + #include "hard-reg-set.h" + #include "real.h" + #include "insn-config.h" + #include "conditions.h" + #include "insn-flags.h" + #include "output.h" + #include "insn-attr.h" + #include "tree.h" + #include "flags.h" + #include "except.h" + #include "function.h" + #include "recog.h" + #include "expr.h" + #include "c-tree.h" + #include "toplev.h" + + tree char_array_type_node; + + /* 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)) + + #include + /* Offset to end of allocated area of stack frame. It is defined in the function.c. */ + extern HOST_WIDE_INT frame_offset; + /* List of trampolines */ + extern tree query_trampoline_list(); + + + /* This file contains the several memory re-allocation in order to protect the return + address and the frame pointer of the stack from a stack-smashing attack. It also + provides the function that protects variables of function pointer. */ + + /* 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 int search_string_from_argsandvars (void); + static int search_string_from_local_vars (tree block); + static int search_string_def (tree names); + static int search_pointer_def (tree names); + static void reset_used_flags_for_insns (rtx insn); + static void reset_used_flags_for_decls (tree block); + static void reset_used_flags_of_plus (rtx x); + static void rtl_prologue (rtx insn); + static void rtl_epilogue (rtx fnlastinsn); + static void arrange_var_order (tree blocks); + static void copy_args_for_protection (void); + static void sweep_string_variable (rtx sweep_var, int var_size); + static void sweep_string_in_decls (tree block, int sweep_offset, int size); + static void sweep_string_in_args (tree parms, int sweep_offset, int size); + static void sweep_string_use_of_insns (rtx insn, int sweep_offset, int size); + static void sweep_string_in_operand (rtx orig, int sweep_offset, int size); + static void move_arg_location (rtx insn, rtx orig, rtx new, int var_size); + static void change_arg_use_of_insns (rtx insn, rtx orig, rtx new, int size); + static void change_arg_use_in_operand (rtx x, rtx orig, rtx new, int size); + static void expand_value_return (rtx val); + static int replace_return_reg (rtx insn, rtx return_save); + static void mark_based_rtx (rtx insn); + static int mark_based_rtx_in_operand (rtx x); + + + #define SUSPICIOUS_BUF_SIZE 10 + static FILE *fstr = NULL; + static char *debugtype = NULL; + + #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 + previous_frame_offset = frame_offset; + + /* the location must be before buffers */ + guard_area = assign_stack_local (SImode, UNITS_PER_WORD, 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_WORD); + + + /* 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_WORD); + #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 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: + 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 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: + return ! TYPE_READONLY (TREE_TYPE (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 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; + 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)) + { + 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 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; + + 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 (SImode, 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; + rtx return_reg = DECL_RTL (DECL_RESULT (current_function_decl)), return_save; + int i, j; + + handler = gen_rtx_MEM (FUNCTION_MODE, gen_rtx (SYMBOL_REF, Pmode, "__stack_smash_handler")); + + start_sequence (); + + if (return_reg + && ! (current_function_returns_struct + || current_function_returns_pcc_struct)) + { + return_save = gen_reg_rtx (GET_MODE (return_reg)); + + if (! replace_return_reg (prologue_insert_point, return_save)) + emit_move_insn (return_save, return_reg); + } + + compare_from_rtx (guard_area, _guard, NE, 0, SImode, 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) = char_array_type_node; + funcname = output_constant_def( funcstr); + + addr = gen_push_operand (); + emit_move_insn (gen_rtx_MEM (SImode, addr), XEXP (funcname, 0)); /* push current_function_name */ + + addr = gen_push_operand (); + emit_move_insn (gen_rtx_MEM (SImode, addr), guard_area); /* push the value of guard area */ + + /* calculate the stack size of two arguments */ + args_size = GET_MODE_SIZE (SImode) * 2; + #ifdef PUSH_ROUNDING + args_size = PUSH_ROUNDING (GET_MODE_SIZE (SImode)) * 2; + #endif + #ifdef STACK_BOUNDARY + args_size = (((args_size + (STACK_BYTES - 1)) / STACK_BYTES) * STACK_BYTES); + #endif + + /* stack smash handler */ + emit_call_insn (gen_call (handler, GEN_INT (args_size), const0_rtx)); /* jump to the stack smash handler */ + + /* 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) + { + if (!current_function_returns_struct && !current_function_returns_pcc_struct) + expand_value_return (return_save); + + + /* If returning a structure, arrange to return the address of the value + in a place where debuggers expect to find it. + + If returning a structure PCC style, + the caller also depends on this value. + And current_function_returns_pcc_struct is not necessarily set. */ + else { + rtx value_address = XEXP (DECL_RTL (DECL_RESULT (current_function_decl)), 0); + tree type = TREE_TYPE (DECL_RESULT (current_function_decl)); + #ifdef FUNCTION_OUTGOING_VALUE + rtx outgoing + = FUNCTION_OUTGOING_VALUE (build_pointer_type (type), + current_function_decl); + #else + rtx outgoing + = FUNCTION_VALUE (build_pointer_type (type), + current_function_decl); + #endif + + /* Mark this as a function return value so integrate will delete the + assignment and USE below when inlining this function. */ + REG_FUNCTION_VALUE_P (outgoing) = 1; + + emit_move_insn (outgoing, value_address); + use_variable (outgoing); + } + } + + _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 saving_insns; + rtx temp_rtx; + + /* refer: dbxout_parms */ + 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)) + { + int string_p; + tree fntype; + + /* + skip arguemnt protection if the last argument is used + for the variable argument + */ + /* + 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; + } + */ + + + 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 processed in gcse.c (COPY-PROP)*/ + + change_arg_use_of_insns (prologue_insert_point, DECL_RTL (parms), safe, 0); + + /* change debugger info */ + DECL_RTL (parms) = safe; + + DECL_INCOMING_RTL (parms) = 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 processed in gcse.c (COPY-PROP)*/ + + /* change the addressof information to the newly allocated pseudo register */ + emit_move_insn (DECL_RTL (parms), safe); + + /* change debugger info */ + DECL_RTL (parms) = safe; + + DECL_INCOMING_RTL (parms) = 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; + 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; + + 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; + 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; + + 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); + } + } + + + + /* + check the register usage + */ + static void + mark_based_rtx (insn) + rtx insn; + { + int i; + rtx body; + + for (; insn; insn = NEXT_INSN (insn)) + if (GET_CODE (insn) == INSN) + { + body = PATTERN (insn); + if (GET_CODE (body) == SET) + mark_based_rtx_in_operand (body); + + else if (GET_CODE (body) == PARALLEL) + { + for (i = XVECLEN (body, 0) - 1; i >= 0; --i) + if (GET_CODE (XVECEXP (body, 0, i)) == SET) + mark_based_rtx_in_operand (XVECEXP (body, 0, i)); + } + } + } + + + static int + mark_based_rtx_in_operand (x) + rtx x; + { + register enum rtx_code code; + int offset, i, j; + char *fmt; + + if (x == 0) + return; + + code = GET_CODE (x); + + switch (code) + { + case SET: + if (mark_based_rtx_in_operand (XEXP (x, 1))) + { + if (GET_CODE (XEXP (x, 0)) == REG) + XEXP (x, 0)->frame_related = 1; + }; + break; + + case PLUS: + if (XEXP (x, 0) == virtual_stack_vars_rtx + || XEXP (x, 0)->frame_related) + { + if (GET_CODE (XEXP (x, 1)) == REG && XEXP (x, 1)->frame_related == 0) + return TRUE; + else if (CONSTANT_P (XEXP (x, 1)) && DEBUGGER_AUTO_OFFSET(x) > 0) + return TRUE; + } + break; + + default: + break; + } + return FALSE; + } + + static int + replace_return_reg (first, return_save) + rtx first, return_save; + { + rtx return_reg = DECL_RTL (DECL_RESULT (current_function_decl)); + rtx insn; + + /* comfirm that insn patterns are the expected order */ + for (insn = first; insn; insn = NEXT_INSN (insn)) + { + if (GET_RTX_CLASS (GET_CODE (insn)) == 'i') + { + rtx prev; + + if (PREV_INSN (insn)) prev = PREV_INSN (insn); + + if (GET_CODE (PATTERN (insn)) == USE && XEXP (PATTERN (insn), 0) == return_reg) + if (!(prev && GET_CODE (PATTERN (prev)) == SET && XEXP (PATTERN (prev), 0) == return_reg)) + return FALSE; + } + } + + /* replace return register */ + for (insn = first; insn; insn = NEXT_INSN (insn)) + { + if (GET_RTX_CLASS (GET_CODE (insn)) == 'i') + { + rtx prev; + + if (PREV_INSN (insn)) prev = PREV_INSN (insn); + if (GET_CODE (PATTERN (insn)) == USE && XEXP (PATTERN (insn), 0) == return_reg + && prev && GET_CODE (PATTERN (prev)) == SET && XEXP (PATTERN (prev), 0) == return_reg) + { + XEXP (PATTERN (prev), 0) = return_save; + + /* change use insn to NOTE_INSN_DELETED */ + PUT_CODE (insn, NOTE); + NOTE_SOURCE_FILE (insn) = 0; + NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED; + } + } + } + + return TRUE; + } + + + /* + Generate RTL to return from the current function, with value VAL. + It is copied and modified based on expand_value_return function of stmt.c + */ + + static void + expand_value_return (val) + rtx val; + { + rtx return_reg = DECL_RTL (DECL_RESULT (current_function_decl)); + + /* Copy the value to the return location + unless it's already there. */ + + if (return_reg != val) + { + #ifdef PROMOTE_FUNCTION_RETURN + tree type = TREE_TYPE (DECL_RESULT (current_function_decl)); + int unsignedp = TREE_UNSIGNED (type); + enum machine_mode mode + = promote_mode (type, DECL_MODE (DECL_RESULT (current_function_decl)), + &unsignedp, 1); + + if (GET_MODE (val) != VOIDmode && GET_MODE (val) != mode) + convert_move (return_reg, val, unsignedp); + else + #endif + emit_move_insn (return_reg, val); + } + if (GET_CODE (return_reg) == REG + && REGNO (return_reg) < FIRST_PSEUDO_REGISTER) + emit_insn (gen_rtx_USE (VOIDmode, return_reg)); + /* Handle calls that return values in multiple non-contiguous locations. + The Irix 6 ABI has examples of this. */ + else if (GET_CODE (return_reg) == PARALLEL) + { + int i; + + for (i = 0; i < XVECLEN (return_reg, 0); i++) + { + rtx x = XEXP (XVECEXP (return_reg, 0, i), 0); + + if (GET_CODE (x) == REG + && REGNO (x) < FIRST_PSEUDO_REGISTER) + emit_insn (gen_rtx_USE (VOIDmode, x)); + } + } + } + + + + + + + + /* + 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. + */ + static void push_frame (int var_size); + static void push_frame_in_decls (tree block, int push_size); + static void push_frame_in_args (tree parms, int push_size); + static void push_frame_of_insns (rtx insn, int push_size); + static void push_frame_in_operand (rtx orig, int push_size); + static void push_frame_of_reg_equiv_memory_loc (int push_size); + static void push_frame_of_reg_equiv_constant (int push_size); + static void reset_used_flags_for_push_frame (); + + + 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; + extern int flag_propolice_protection; /* Nonzero means use ProPolice as a stack protection method */ + + 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 + } + + + /* + 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; + { + #ifndef FRAME_GROWS_DOWNWARD + 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(); + #endif + } + + 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; + 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; + + 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; + } + } + } + } +