With a new libgo patch (waiting to be committed until we are out of stage 4) I noticed that the runtime/pprof tests were failing about 2% of the time on 32-bit x86. The problem turned out to be testing profiling with a very call-heavy benchmark. The 32-bit x86 split stack sequence pushes two numbers on the stack as arguments to the __morestack function. GCC was not generating unwind information for those push instructions. When the SIGPROF signal was delivered while executing the second push instruction or the call instruction, the unwinder would be unable to locate the PC and would crash.
Fortunately this is easy to fix as the instructions always run at the very beginning of the function, before any stack manipulation has occurred. I have committed this patch to fix the problem. Bootstrapped on x86_64-pc-linux-gnu. Ran the Go testsuite and all the split-stack tests in both 32-bit and 64-bit mode. Ian 2017-01-31 Ian Lance Taylor <i...@golang.org> * config/i386/i386.c (ix86_expand_split_stack_prologue): Add REG_ARGS_SIZE note to 32-bit push insns and call insn.
Index: gcc/config/i386/i386.c =================================================================== --- gcc/config/i386/i386.c (revision 244456) +++ gcc/config/i386/i386.c (working copy) @@ -14944,6 +14944,7 @@ ix86_expand_split_stack_prologue (void) allocate_rtx = GEN_INT (allocate); args_size = crtl->args.size >= 0 ? crtl->args.size : 0; call_fusage = NULL_RTX; + rtx pop = NULL_RTX; if (TARGET_64BIT) { rtx reg10, reg11; @@ -15021,13 +15022,18 @@ ix86_expand_split_stack_prologue (void) } else { - emit_insn (gen_push (GEN_INT (args_size))); - emit_insn (gen_push (allocate_rtx)); + rtx_insn *insn = emit_insn (gen_push (GEN_INT (args_size))); + add_reg_note (insn, REG_ARGS_SIZE, GEN_INT (UNITS_PER_WORD)); + insn = emit_insn (gen_push (allocate_rtx)); + add_reg_note (insn, REG_ARGS_SIZE, GEN_INT (2 * UNITS_PER_WORD)); + pop = GEN_INT (2 * UNITS_PER_WORD); } call_insn = ix86_expand_call (NULL_RTX, gen_rtx_MEM (QImode, fn), GEN_INT (UNITS_PER_WORD), constm1_rtx, - NULL_RTX, false); + pop, false); add_function_usage_to (call_insn, call_fusage); + if (!TARGET_64BIT) + add_reg_note (call_insn, REG_ARGS_SIZE, GEN_INT (0)); /* In order to make call/return prediction work right, we now need to execute a return instruction. See