| Index: gcc/gcc/ctrl-intg.c
|
| diff --git a/gcc/gcc/ctrl-intg.c b/gcc/gcc/ctrl-intg.c
|
| deleted file mode 100644
|
| index 61e10198c5dbe34a1f99332bf8825fcd715c5d93..0000000000000000000000000000000000000000
|
| --- a/gcc/gcc/ctrl-intg.c
|
| +++ /dev/null
|
| @@ -1,376 +0,0 @@
|
| -/* Patch RTL to enforce control flow integrity for GCC.
|
| - Copyright (C) 1987, 1988, 1992, 1997, 1998, 1999, 2000, 2002, 2003,
|
| - 2004, 2005, 2007
|
| - Free Software Foundation, Inc.
|
| -
|
| -This file is part of GCC.
|
| -
|
| -GCC is free software; you can redistribute it and/or modify it under
|
| -the terms of the GNU General Public License as published by the Free
|
| -Software Foundation; either version 3, or (at your option) any later
|
| -version.
|
| -
|
| -GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
| -WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
| -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
| -for more details.
|
| -
|
| -You should have received a copy of the GNU General Public License
|
| -along with GCC; see the file COPYING3. If not see
|
| -<http://www.gnu.org/licenses/>. */
|
| -
|
| -/* This file is compiled twice: once for the generator programs,
|
| - once for the compiler. */
|
| -#ifdef GENERATOR_FILE
|
| -#include "bconfig.h"
|
| -#else
|
| -#include "config.h"
|
| -#endif
|
| -
|
| -#include "system.h"
|
| -#include "coretypes.h"
|
| -#include "tm.h"
|
| -#include "rtl.h"
|
| -#include "tree-pass.h"
|
| -#include "expr.h"
|
| -
|
| -/* These headers all define things which are not available in
|
| - generator programs. */
|
| -#ifndef GENERATOR_FILE
|
| -#include "tree.h"
|
| -#include "real.h"
|
| -#include "flags.h"
|
| -#include "hard-reg-set.h"
|
| -#include "basic-block.h"
|
| -#endif
|
| -
|
| -static bool
|
| -gate_func (void) {
|
| - return getenv("NACLSHUTDOWN") == NULL;
|
| - /* return flag_control_integrity; */
|
| -}
|
| -
|
| -static void
|
| -process_call_insn(rtx insn) {
|
| - rtx return_value_expr, call_expr, mem_expr, addr_expr, parallel_expr;
|
| - rtx sp_size_expr, tls_disp;
|
| -
|
| - /*
|
| - * Get the expression to be examined from the instruction.
|
| - */
|
| - call_expr = XEXP (insn, 5);
|
| -
|
| - if (GET_CODE (call_expr) == PARALLEL) {
|
| - /*
|
| - * Calls that pop the stack use a PARALLEL containing a CALL and a SET.
|
| - */
|
| - rtx vec1 = XVECEXP (call_expr, 0, 1);
|
| - parallel_expr = call_expr;
|
| - tls_disp = NULL_RTX;
|
| -
|
| - if (TARGET_64BIT &&
|
| - GET_CODE(vec1) == UNSPEC && XINT(vec1, 1) == UNSPEC_TPOFF) {
|
| - /*
|
| - * TLS calls use a PARALLEL containing a CALL and UNSPEC_TPOFF.
|
| - */
|
| - tls_disp = XVECEXP(vec1, 0, 0);
|
| - gcc_assert(GET_CODE(tls_disp) == SYMBOL_REF);
|
| - } else {
|
| - sp_size_expr = XEXP (XEXP (vec1, 1), 1);
|
| - }
|
| - call_expr = XVECEXP (call_expr, 0, 0);
|
| - }
|
| - else {
|
| - parallel_expr = NULL_RTX;
|
| - }
|
| -
|
| - /*
|
| - * Get the call expression and return value (if any).
|
| - */
|
| - if (GET_CODE (call_expr) == SET) {
|
| - /*
|
| - * Functions with return values use a SET instruction wrapper.
|
| - * Get the call out of the set if needed.
|
| - */
|
| - return_value_expr = XEXP (call_expr, 0);
|
| - call_expr = XEXP (call_expr, 1);
|
| - }
|
| - else {
|
| - return_value_expr = NULL_RTX;
|
| - }
|
| -
|
| - /*
|
| - * Extract the target address expression of the function.
|
| - */
|
| - mem_expr = XEXP (call_expr, 0);
|
| -
|
| - /*
|
| - * Get the address expression from the MEM.
|
| - */
|
| -
|
| - gcc_assert (GET_CODE (mem_expr) == MEM);
|
| - addr_expr = XEXP (mem_expr, 0);
|
| -
|
| - if (GET_CODE (addr_expr) != SYMBOL_REF) {
|
| - rtx insns_head, call, call_insn;
|
| - int enable_print;
|
| -
|
| - {
|
| - static int calls_converted=0;
|
| - static int printed=0;
|
| - char* call_limit = getenv("NONACLCALL");
|
| - char* name_compare = getenv("NACLBINS");
|
| - if (name_compare && strcmp(main_input_filename, name_compare) > 0) {
|
| - if (printed == 0) {
|
| - fprintf(stderr, "NACL: name test shut off\n");
|
| - printed = 1;
|
| - }
|
| - return;
|
| - }
|
| -
|
| - ++calls_converted;
|
| - enable_print = (call_limit && calls_converted == atoi(call_limit));
|
| - if (call_limit && calls_converted > atoi(call_limit)) {
|
| - if (printed == 0) {
|
| - fprintf(stderr, "NACL: '%s' call limit exceeded\n",
|
| - main_input_filename);
|
| - printed = 1;
|
| - }
|
| - return;
|
| - }
|
| - /* fprintf(stderr, "NACL: converted call %d\n", calls_converted); */
|
| - }
|
| -
|
| - if (return_value_expr && parallel_expr) {
|
| - if (getenv("NACLDBGBOTH")) return;
|
| - } else if (return_value_expr) {
|
| - if (getenv("NACLDBGRET")) return;
|
| - } else if (parallel_expr) {
|
| - if (getenv("NACLDBGPAR")) return;
|
| - } else {
|
| - if (SIBLING_CALL_P (insn)) {
|
| - if (getenv("NACLDBGNONE1")) return;
|
| - } else {
|
| - char* str = getenv("NACLDBGNONE2");
|
| - if (str) {
|
| - FILE* fp = fopen("/home/sehr/NACLDBGCOUNT", "r+");
|
| - int current_count;
|
| - fscanf(fp, "%d\n", ¤t_count);
|
| - fprintf(stderr, "NACLDEBUGCOUNT = %d \n", current_count);
|
| - rewind(fp);
|
| - fprintf(fp, "%d\n", current_count+1);
|
| - fclose(fp);
|
| - if (current_count > atoi(str)) {
|
| - fprintf(stderr, "NACLDEBUGCOUNT %d exceeded %d\n",
|
| - current_count, atoi(str));
|
| - return;
|
| - }
|
| - }
|
| - }
|
| - }
|
| -
|
| - start_sequence ();
|
| -
|
| - if (enable_print) {
|
| - fprintf(stderr, "Before:\n");
|
| - print_rtl_single(stderr, insn);
|
| - }
|
| -
|
| - /*
|
| - * Force the called function address to be in a register.
|
| - */
|
| - addr_expr = force_reg (GET_MODE (addr_expr), addr_expr);
|
| -
|
| -#define gen_nacl(suffix) \
|
| - (TARGET_64BIT ? gen_nacl ## suffix ## di : \
|
| - gen_nacl ## suffix ## si)
|
| - /*
|
| - * Generate the appropriate template for the call
|
| - */
|
| - if (return_value_expr && parallel_expr) {
|
| - if (!tls_disp) {
|
| - call = gen_nacl(call_value_pop) (return_value_expr, addr_expr,
|
| - XEXP (call_expr, 1), sp_size_expr);
|
| - } else {
|
| - call = gen_naclcall_tls(mem_expr, XEXP (call_expr, 1));
|
| - }
|
| - } else if (return_value_expr) {
|
| - if (SIBLING_CALL_P (insn)) {
|
| - call = gen_nacl(sibcall_value) (return_value_expr,
|
| - addr_expr, XEXP (call_expr, 1));
|
| - } else {
|
| - call = gen_nacl(call_value) (return_value_expr,
|
| - addr_expr, XEXP (call_expr, 1));
|
| - }
|
| - } else if (parallel_expr) {
|
| - call = gen_nacl(call_pop) (addr_expr, XEXP (call_expr, 1),
|
| - sp_size_expr);
|
| - } else {
|
| - if (SIBLING_CALL_P (insn)) {
|
| - call = gen_nacl(sibcall) (addr_expr, XEXP (call_expr, 1));
|
| - } else {
|
| - call = gen_nacl(call) (addr_expr, XEXP (call_expr, 1));
|
| - }
|
| - }
|
| -
|
| - call_insn = emit_call_insn (call);
|
| -
|
| - RTL_CONST_CALL_P (call_insn) = RTL_CONST_CALL_P (insn);
|
| - RTL_PURE_CALL_P (call_insn) = RTL_PURE_CALL_P (insn);
|
| - SIBLING_CALL_P (call_insn) = SIBLING_CALL_P (insn);
|
| - REG_NOTES (call_insn) = REG_NOTES (insn);
|
| - CALL_INSN_FUNCTION_USAGE (call_insn) = CALL_INSN_FUNCTION_USAGE (insn);
|
| -
|
| - insns_head = get_insns ();
|
| -
|
| - if (enable_print) {
|
| - fprintf(stderr, "After: (%d, %d) \n", RTL_CONST_OR_PURE_CALL_P (call_insn),
|
| - SIBLING_CALL_P (call_insn));
|
| - print_rtl(stderr, insns_head);
|
| - }
|
| -
|
| - end_sequence ();
|
| - emit_insn_before (insns_head, insn);
|
| -
|
| - delete_insn (insn);
|
| - }
|
| -}
|
| -
|
| -
|
| -static void
|
| -process_jump_insn(rtx insn) {
|
| - rtx par_expr, set_expr, addr_expr;
|
| - rtx jmp;
|
| -
|
| - /*
|
| - * Get the contained expression.
|
| - */
|
| - par_expr = XEXP (insn, 5);
|
| -
|
| - if (GET_CODE (par_expr) == PARALLEL) {
|
| - set_expr = XVECEXP (par_expr, 0, 0);
|
| -
|
| - if (GET_CODE (set_expr) == SET) {
|
| - addr_expr = XEXP (set_expr, 1);
|
| -
|
| - if (GET_CODE (addr_expr) == IF_THEN_ELSE) {
|
| - /*
|
| - * Ordinary branches uses parallel/set/if_then_else.
|
| - * Leave them unmodified.
|
| - */
|
| - }
|
| - else {
|
| - /*
|
| - * A table indirect jump instruction has parallel/set/other
|
| - */
|
| - rtx insns_head, jmp_insn;
|
| - int enable_print;
|
| -
|
| - {
|
| - static int calls_converted=0;
|
| - static int printed=0;
|
| - char* name_compare = getenv("NACLBINS");
|
| - char* call_limit = getenv("NONACLJMP");
|
| - if (name_compare && strcmp(main_input_filename, name_compare) > 0) {
|
| - fprintf(stderr, "NACL: name test shut off\n");
|
| - return;
|
| - }
|
| -
|
| - ++calls_converted;
|
| - enable_print = (call_limit && calls_converted == atoi(call_limit));
|
| - if (call_limit && calls_converted > atoi(call_limit)) {
|
| - if (printed == 0) {
|
| - fprintf(stderr, "NACL: '%s' call limit exceeded\n",
|
| - main_input_filename);
|
| - printed = 1;
|
| - }
|
| - return;
|
| - }
|
| - /*fprintf(stderr, "NACL: converted branch %d\n", calls_converted);*/
|
| - }
|
| -
|
| - start_sequence ();
|
| -
|
| - if (enable_print) {
|
| - fprintf(stderr, "Before:\n");
|
| - print_rtl_single(stderr, insn);
|
| - }
|
| - addr_expr = force_reg (GET_MODE (addr_expr), addr_expr);
|
| - jmp = gen_nacl(jmp_table) (addr_expr,
|
| - XEXP (XEXP (XVECEXP (par_expr, 0, 1), 0), 0));
|
| - jmp_insn = emit_jump_insn (jmp);
|
| -
|
| - if (JUMP_LABEL (insn) != NULL_RTX) {
|
| - JUMP_LABEL (jmp_insn) = JUMP_LABEL (insn);
|
| - LABEL_NUSES (JUMP_LABEL (insn))++;
|
| - }
|
| -
|
| - insns_head = get_insns ();
|
| - if (enable_print) {
|
| - fprintf(stderr, "After %p:\n", (void*) JUMP_LABEL (jmp_insn));
|
| - print_rtl(stderr, insns_head);
|
| - }
|
| -
|
| - end_sequence ();
|
| - emit_insn_before (insns_head, insn);
|
| -
|
| - delete_insn (insn);
|
| - }
|
| - }
|
| - } else {
|
| - /*
|
| - * Other indirect jumps remain to be identified.
|
| - */
|
| - }
|
| -}
|
| -
|
| -extern int nacl_special_commands;
|
| -
|
| -static int
|
| -execute_func (void) {
|
| - basic_block bb;
|
| -
|
| - int save_nacl_special_commands = nacl_special_commands;
|
| - nacl_special_commands = 1;
|
| -
|
| - if (getenv("NACLSHUTDOWN4")) return 0;
|
| - /* Even if reload is not yet completed - fake it to make reload impossible */
|
| - FOR_EACH_BB (bb) {
|
| - rtx insn, last;
|
| -
|
| - if (getenv("NACLSHUTDOWN3")) continue;
|
| - for (insn = BB_HEAD (bb), last = NEXT_INSN (BB_END (bb)); insn != last;
|
| - insn = NEXT_INSN(insn)) {
|
| - if (getenv("NACLSHUTDOWN2")) continue;
|
| - if (JUMP_P (insn)) {
|
| - if (flag_control_integrity)
|
| - process_jump_insn (insn);
|
| - }
|
| - if (CALL_P (insn)) {
|
| - if (flag_control_integrity)
|
| - process_call_insn (insn);
|
| - }
|
| - }
|
| - }
|
| -
|
| - nacl_special_commands = save_nacl_special_commands;
|
| - return 0;
|
| -}
|
| -
|
| -struct rtl_opt_pass pass_control_integrity = {
|
| - {
|
| - RTL_PASS,
|
| - "ctrl_intg_insert",
|
| - gate_func,
|
| - execute_func,
|
| - 0, /* sub */
|
| - 0, /* next */
|
| - 0, /* static_pass_number */
|
| - 0, /* tv_id */
|
| - 0, /* properties_required */
|
| - 0, /* properties_provided */
|
| - 0, /* properties_destroyed */
|
| - TODO_dump_func, /* todo_flags_start */
|
| - TODO_dump_func, /* todo_flags_finish */
|
| - }
|
| -};
|
|
|