^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * Copyright 2011-2017 by the PaX Team <pageexec@freemail.hu>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Modified by Alexander Popov <alex.popov@linux.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Licensed under the GPL v2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Note: the choice of the license means that the compilation process is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * NOT 'eligible' as defined by gcc's library exception to the GPL v3,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * but for the kernel it doesn't matter since it doesn't link against
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * any of the gcc libraries
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * This gcc plugin is needed for tracking the lowest border of the kernel stack.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * It instruments the kernel code inserting stackleak_track_stack() calls:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * - after alloca();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * - for the functions with a stack frame size greater than or equal
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * to the "track-min-size" plugin parameter.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * This plugin is ported from grsecurity/PaX. For more information see:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * https://grsecurity.net/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * https://pax.grsecurity.net/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * Debugging:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * - use fprintf() to stderr, debug_generic_expr(), debug_gimple_stmt(),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) * print_rtl_single() and debug_rtx();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) * - add "-fdump-tree-all -fdump-rtl-all" to the plugin CFLAGS in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) * Makefile.gcc-plugins to see the verbose dumps of the gcc passes;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) * - use gcc -E to understand the preprocessing shenanigans;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) * - use gcc with enabled CFG/GIMPLE/SSA verification (--enable-checking).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include "gcc-common.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) __visible int plugin_is_GPL_compatible;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) static int track_frame_size = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) static bool build_for_x86 = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) static const char track_function[] = "stackleak_track_stack";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) static bool disable = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) static bool verbose = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) * Mark these global variables (roots) for gcc garbage collector since
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) * they point to the garbage-collected memory.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) static GTY(()) tree track_function_decl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) static struct plugin_info stackleak_plugin_info = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) .version = "201707101337",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) .help = "track-min-size=nn\ttrack stack for functions with a stack frame size >= nn bytes\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) "arch=target_arch\tspecify target build arch\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) "disable\t\tdo not activate the plugin\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) "verbose\t\tprint info about the instrumentation\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) static void add_stack_tracking_gcall(gimple_stmt_iterator *gsi, bool after)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) gimple stmt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) gcall *gimple_call;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) cgraph_node_ptr node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) basic_block bb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) /* Insert calling stackleak_track_stack() */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) stmt = gimple_build_call(track_function_decl, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) gimple_call = as_a_gcall(stmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) if (after)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) gsi_insert_after(gsi, gimple_call, GSI_CONTINUE_LINKING);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) gsi_insert_before(gsi, gimple_call, GSI_SAME_STMT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) /* Update the cgraph */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) bb = gimple_bb(gimple_call);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) node = cgraph_get_create_node(track_function_decl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) gcc_assert(node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) cgraph_create_edge(cgraph_get_node(current_function_decl), node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) gimple_call, bb->count,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) compute_call_stmt_bb_frequency(current_function_decl, bb));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) static bool is_alloca(gimple stmt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) if (gimple_call_builtin_p(stmt, BUILT_IN_ALLOCA))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) #if BUILDING_GCC_VERSION >= 4007
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) if (gimple_call_builtin_p(stmt, BUILT_IN_ALLOCA_WITH_ALIGN))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) static tree get_current_stack_pointer_decl(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) varpool_node_ptr node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) FOR_EACH_VARIABLE(node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) tree var = NODE_DECL(node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) tree name = DECL_NAME(var);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) if (DECL_NAME_LENGTH(var) != sizeof("current_stack_pointer") - 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) if (strcmp(IDENTIFIER_POINTER(name), "current_stack_pointer"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) return var;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) if (verbose) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) fprintf(stderr, "stackleak: missing current_stack_pointer in %s()\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) DECL_NAME_POINTER(current_function_decl));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) return NULL_TREE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) static void add_stack_tracking_gasm(gimple_stmt_iterator *gsi, bool after)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) gasm *asm_call = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) tree sp_decl, input;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) vec<tree, va_gc> *inputs = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) /* 'no_caller_saved_registers' is currently supported only for x86 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) gcc_assert(build_for_x86);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) * Insert calling stackleak_track_stack() in asm:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) * asm volatile("call stackleak_track_stack"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) * :: "r" (current_stack_pointer))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) * Use ASM_CALL_CONSTRAINT trick from arch/x86/include/asm/asm.h.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) * This constraint is taken into account during gcc shrink-wrapping
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) * optimization. It is needed to be sure that stackleak_track_stack()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) * call is inserted after the prologue of the containing function,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) * when the stack frame is prepared.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) sp_decl = get_current_stack_pointer_decl();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) if (sp_decl == NULL_TREE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) add_stack_tracking_gcall(gsi, after);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) input = build_tree_list(NULL_TREE, build_const_char_string(2, "r"));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) input = chainon(NULL_TREE, build_tree_list(input, sp_decl));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) vec_safe_push(inputs, input);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) asm_call = gimple_build_asm_vec("call stackleak_track_stack",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) inputs, NULL, NULL, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) gimple_asm_set_volatile(asm_call, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) if (after)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) gsi_insert_after(gsi, asm_call, GSI_CONTINUE_LINKING);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) gsi_insert_before(gsi, asm_call, GSI_SAME_STMT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) update_stmt(asm_call);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) static void add_stack_tracking(gimple_stmt_iterator *gsi, bool after)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) * The 'no_caller_saved_registers' attribute is used for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) * stackleak_track_stack(). If the compiler supports this attribute for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) * the target arch, we can add calling stackleak_track_stack() in asm.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) * That improves performance: we avoid useless operations with the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) * caller-saved registers in the functions from which we will remove
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) * stackleak_track_stack() call during the stackleak_cleanup pass.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) if (lookup_attribute_spec(get_identifier("no_caller_saved_registers")))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) add_stack_tracking_gasm(gsi, after);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) add_stack_tracking_gcall(gsi, after);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) * Work with the GIMPLE representation of the code. Insert the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) * stackleak_track_stack() call after alloca() and into the beginning
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) * of the function if it is not instrumented.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) static unsigned int stackleak_instrument_execute(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) basic_block bb, entry_bb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) bool prologue_instrumented = false, is_leaf = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) gimple_stmt_iterator gsi = { 0 };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) * ENTRY_BLOCK_PTR is a basic block which represents possible entry
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) * point of a function. This block does not contain any code and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) * has a CFG edge to its successor.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) gcc_assert(single_succ_p(ENTRY_BLOCK_PTR_FOR_FN(cfun)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) entry_bb = single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) * Loop through the GIMPLE statements in each of cfun basic blocks.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) * cfun is a global variable which represents the function that is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) * currently processed.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) FOR_EACH_BB_FN(bb, cfun) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) for (gsi = gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) gimple stmt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) stmt = gsi_stmt(gsi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) /* Leaf function is a function which makes no calls */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) if (is_gimple_call(stmt))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) is_leaf = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) if (!is_alloca(stmt))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) if (verbose) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) fprintf(stderr, "stackleak: be careful, alloca() in %s()\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) DECL_NAME_POINTER(current_function_decl));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) /* Insert stackleak_track_stack() call after alloca() */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) add_stack_tracking(&gsi, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) if (bb == entry_bb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) prologue_instrumented = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) if (prologue_instrumented)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) * Special cases to skip the instrumentation.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) * Taking the address of static inline functions materializes them,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) * but we mustn't instrument some of them as the resulting stack
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) * alignment required by the function call ABI will break other
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) * assumptions regarding the expected (but not otherwise enforced)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) * register clobbering ABI.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) * Case in point: native_save_fl on amd64 when optimized for size
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) * clobbers rdx if it were instrumented here.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) * TODO: any more special cases?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) if (is_leaf &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) !TREE_PUBLIC(current_function_decl) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) DECL_DECLARED_INLINE_P(current_function_decl)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) if (is_leaf &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) !strncmp(IDENTIFIER_POINTER(DECL_NAME(current_function_decl)),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) "_paravirt_", 10)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) /* Insert stackleak_track_stack() call at the function beginning */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) bb = entry_bb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) if (!single_pred_p(bb)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) /* gcc_assert(bb_loop_depth(bb) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) (bb->flags & BB_IRREDUCIBLE_LOOP)); */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) split_edge(single_succ_edge(ENTRY_BLOCK_PTR_FOR_FN(cfun)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) gcc_assert(single_succ_p(ENTRY_BLOCK_PTR_FOR_FN(cfun)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) bb = single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) gsi = gsi_after_labels(bb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) add_stack_tracking(&gsi, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) static bool large_stack_frame(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) #if BUILDING_GCC_VERSION >= 8000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) return maybe_ge(get_frame_size(), track_frame_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) return (get_frame_size() >= track_frame_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) static void remove_stack_tracking_gcall(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) rtx_insn *insn, *next;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) * Find stackleak_track_stack() calls. Loop through the chain of insns,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) * which is an RTL representation of the code for a function.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) * The example of a matching insn:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) * (call_insn 8 4 10 2 (call (mem (symbol_ref ("stackleak_track_stack")
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) * [flags 0x41] <function_decl 0x7f7cd3302a80 stackleak_track_stack>)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) * [0 stackleak_track_stack S1 A8]) (0)) 675 {*call} (expr_list
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) * (symbol_ref ("stackleak_track_stack") [flags 0x41] <function_decl
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) * 0x7f7cd3302a80 stackleak_track_stack>) (expr_list (0) (nil))) (nil))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) for (insn = get_insns(); insn; insn = next) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) rtx body;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) next = NEXT_INSN(insn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) /* Check the expression code of the insn */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) if (!CALL_P(insn))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) * Check the expression code of the insn body, which is an RTL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) * Expression (RTX) describing the side effect performed by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) * that insn.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) body = PATTERN(insn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) if (GET_CODE(body) == PARALLEL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) body = XVECEXP(body, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) if (GET_CODE(body) != CALL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) * Check the first operand of the call expression. It should
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) * be a mem RTX describing the needed subroutine with a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) * symbol_ref RTX.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) body = XEXP(body, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) if (GET_CODE(body) != MEM)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) body = XEXP(body, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) if (GET_CODE(body) != SYMBOL_REF)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) if (SYMBOL_REF_DECL(body) != track_function_decl)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) /* Delete the stackleak_track_stack() call */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) delete_insn_and_edges(insn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) #if BUILDING_GCC_VERSION >= 4007 && BUILDING_GCC_VERSION < 8000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) if (GET_CODE(next) == NOTE &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) NOTE_KIND(next) == NOTE_INSN_CALL_ARG_LOCATION) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) insn = next;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) next = NEXT_INSN(insn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) delete_insn_and_edges(insn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) static bool remove_stack_tracking_gasm(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) bool removed = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) rtx_insn *insn, *next;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) /* 'no_caller_saved_registers' is currently supported only for x86 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) gcc_assert(build_for_x86);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) * Find stackleak_track_stack() asm calls. Loop through the chain of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) * insns, which is an RTL representation of the code for a function.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) * The example of a matching insn:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) * (insn 11 5 12 2 (parallel [ (asm_operands/v
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) * ("call stackleak_track_stack") ("") 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) * [ (reg/v:DI 7 sp [ current_stack_pointer ]) ]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) * [ (asm_input:DI ("r")) ] [])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) * (clobber (reg:CC 17 flags)) ]) -1 (nil))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) for (insn = get_insns(); insn; insn = next) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) rtx body;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) next = NEXT_INSN(insn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) /* Check the expression code of the insn */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) if (!NONJUMP_INSN_P(insn))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) * Check the expression code of the insn body, which is an RTL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) * Expression (RTX) describing the side effect performed by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) * that insn.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) body = PATTERN(insn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) if (GET_CODE(body) != PARALLEL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) body = XVECEXP(body, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) if (GET_CODE(body) != ASM_OPERANDS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) if (strcmp(ASM_OPERANDS_TEMPLATE(body),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) "call stackleak_track_stack")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) delete_insn_and_edges(insn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) gcc_assert(!removed);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) removed = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) return removed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) * Work with the RTL representation of the code.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) * Remove the unneeded stackleak_track_stack() calls from the functions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) * which don't call alloca() and don't have a large enough stack frame size.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) static unsigned int stackleak_cleanup_execute(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) const char *fn = DECL_NAME_POINTER(current_function_decl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) bool removed = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) * Leave stack tracking in functions that call alloca().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) * Additional case:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) * gcc before version 7 called allocate_dynamic_stack_space() from
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) * expand_stack_vars() for runtime alignment of constant-sized stack
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) * variables. That caused cfun->calls_alloca to be set for functions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) * that in fact don't use alloca().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) * For more info see gcc commit 7072df0aae0c59ae437e.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) * Let's leave such functions instrumented as well.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) if (cfun->calls_alloca) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) if (verbose)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) fprintf(stderr, "stackleak: instrument %s(): calls_alloca\n", fn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) /* Leave stack tracking in functions with large stack frame */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) if (large_stack_frame()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) if (verbose)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) fprintf(stderr, "stackleak: instrument %s()\n", fn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) if (lookup_attribute_spec(get_identifier("no_caller_saved_registers")))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) removed = remove_stack_tracking_gasm();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) if (!removed)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) remove_stack_tracking_gcall();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) * STRING_CST may or may not be NUL terminated:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) * https://gcc.gnu.org/onlinedocs/gccint/Constant-expressions.html
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) static inline bool string_equal(tree node, const char *string, int length)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) if (TREE_STRING_LENGTH(node) < length)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) if (TREE_STRING_LENGTH(node) > length + 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) if (TREE_STRING_LENGTH(node) == length + 1 &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) TREE_STRING_POINTER(node)[length] != '\0')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) return !memcmp(TREE_STRING_POINTER(node), string, length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) #define STRING_EQUAL(node, str) string_equal(node, str, strlen(str))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) static bool stackleak_gate(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) tree section;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) section = lookup_attribute("section",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) DECL_ATTRIBUTES(current_function_decl));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) if (section && TREE_VALUE(section)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) section = TREE_VALUE(TREE_VALUE(section));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) if (STRING_EQUAL(section, ".init.text"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) if (STRING_EQUAL(section, ".devinit.text"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) if (STRING_EQUAL(section, ".cpuinit.text"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) if (STRING_EQUAL(section, ".meminit.text"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) return track_frame_size >= 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) /* Build the function declaration for stackleak_track_stack() */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) static void stackleak_start_unit(void *gcc_data __unused,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) void *user_data __unused)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) tree fntype;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) /* void stackleak_track_stack(void) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) fntype = build_function_type_list(void_type_node, NULL_TREE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) track_function_decl = build_fn_decl(track_function, fntype);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) DECL_ASSEMBLER_NAME(track_function_decl); /* for LTO */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) TREE_PUBLIC(track_function_decl) = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) TREE_USED(track_function_decl) = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) DECL_EXTERNAL(track_function_decl) = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) DECL_ARTIFICIAL(track_function_decl) = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) DECL_PRESERVE_P(track_function_decl) = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) * Pass gate function is a predicate function that gets executed before the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) * corresponding pass. If the return value is 'true' the pass gets executed,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) * otherwise, it is skipped.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) static bool stackleak_instrument_gate(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) return stackleak_gate();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) #define PASS_NAME stackleak_instrument
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) #define PROPERTIES_REQUIRED PROP_gimple_leh | PROP_cfg
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) #define TODO_FLAGS_START TODO_verify_ssa | TODO_verify_flow | TODO_verify_stmts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) #define TODO_FLAGS_FINISH TODO_verify_ssa | TODO_verify_stmts | TODO_dump_func \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) | TODO_update_ssa | TODO_rebuild_cgraph_edges
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) #include "gcc-generate-gimple-pass.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) static bool stackleak_cleanup_gate(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) return stackleak_gate();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) #define PASS_NAME stackleak_cleanup
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) #define TODO_FLAGS_FINISH TODO_dump_func
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) #include "gcc-generate-rtl-pass.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) * Every gcc plugin exports a plugin_init() function that is called right
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) * after the plugin is loaded. This function is responsible for registering
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) * the plugin callbacks and doing other required initialization.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) __visible int plugin_init(struct plugin_name_args *plugin_info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) struct plugin_gcc_version *version)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) const char * const plugin_name = plugin_info->base_name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) const int argc = plugin_info->argc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) const struct plugin_argument * const argv = plugin_info->argv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) int i = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) /* Extra GGC root tables describing our GTY-ed data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) static const struct ggc_root_tab gt_ggc_r_gt_stackleak[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) .base = &track_function_decl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) .nelt = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) .stride = sizeof(track_function_decl),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) .cb = >_ggc_mx_tree_node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) .pchw = >_pch_nx_tree_node
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) LAST_GGC_ROOT_TAB
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) * The stackleak_instrument pass should be executed before the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) * "optimized" pass, which is the control flow graph cleanup that is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) * performed just before expanding gcc trees to the RTL. In former
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) * versions of the plugin this new pass was inserted before the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) * "tree_profile" pass, which is currently called "profile".
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) PASS_INFO(stackleak_instrument, "optimized", 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) PASS_POS_INSERT_BEFORE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) * The stackleak_cleanup pass should be executed before the "*free_cfg"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) * pass. It's the moment when the stack frame size is already final,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) * function prologues and epilogues are generated, and the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) * machine-dependent code transformations are not done.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) PASS_INFO(stackleak_cleanup, "*free_cfg", 1, PASS_POS_INSERT_BEFORE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) if (!plugin_default_version_check(version, &gcc_version)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) error(G_("incompatible gcc/plugin versions"));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) /* Parse the plugin arguments */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) for (i = 0; i < argc; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) if (!strcmp(argv[i].key, "track-min-size")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) if (!argv[i].value) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) error(G_("no value supplied for option '-fplugin-arg-%s-%s'"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) plugin_name, argv[i].key);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) track_frame_size = atoi(argv[i].value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) if (track_frame_size < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) error(G_("invalid option argument '-fplugin-arg-%s-%s=%s'"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) plugin_name, argv[i].key, argv[i].value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) } else if (!strcmp(argv[i].key, "arch")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) if (!argv[i].value) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) error(G_("no value supplied for option '-fplugin-arg-%s-%s'"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) plugin_name, argv[i].key);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) if (!strcmp(argv[i].value, "x86"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) build_for_x86 = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) } else if (!strcmp(argv[i].key, "disable")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) disable = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) } else if (!strcmp(argv[i].key, "verbose")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) verbose = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) error(G_("unknown option '-fplugin-arg-%s-%s'"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) plugin_name, argv[i].key);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) if (disable) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) if (verbose)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) fprintf(stderr, "stackleak: disabled for this translation unit\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) /* Give the information about the plugin */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) register_callback(plugin_name, PLUGIN_INFO, NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) &stackleak_plugin_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) /* Register to be called before processing a translation unit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) register_callback(plugin_name, PLUGIN_START_UNIT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) &stackleak_start_unit, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) /* Register an extra GCC garbage collector (GGC) root table */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) register_callback(plugin_name, PLUGIN_REGISTER_GGC_ROOTS, NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) (void *)>_ggc_r_gt_stackleak);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) * Hook into the Pass Manager to register new gcc passes.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) * The stack frame size info is available only at the last RTL pass,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) * when it's too late to insert complex code like a function call.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) * So we register two gcc passes to instrument every function at first
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) * and remove the unneeded instrumentation later.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) &stackleak_instrument_pass_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) &stackleak_cleanup_pass_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) }