Support instrumenting returns of instrumented functions
authorAndi Kleen <ak@linux.intel.com>
Thu, 29 Nov 2018 23:11:47 +0000 (23:11 +0000)
committerAndi Kleen <ak@gcc.gnu.org>
Thu, 29 Nov 2018 23:11:47 +0000 (23:11 +0000)
When instrumenting programs using __fentry__ it is often useful
to instrument the function return too. Traditionally this
has been done by patching the return address on the stack
frame on entry. However this is fairly complicated (trace
function has to emulate a stack) and also slow because
it causes a branch misprediction on every return.

Add an option to generate call or nop instrumentation for
every return instead, including patch sections.

This will increase the program size slightly, but can be a
lot faster and simpler.

This version only instruments true returns, not sibling
calls or tail recursion. This matches the semantics of the
original stack.

gcc/:

2018-11-29  Andi Kleen  <ak@linux.intel.com>

* config/i386/i386-opts.h (enum instrument_return): Add.
* config/i386/i386.c (output_return_instrumentation): Add.
(ix86_output_function_return): Call output_return_instrumentation.
(ix86_output_call_insn): Call output_return_instrumentation.
* config/i386/i386.opt: Add -minstrument-return=.
* doc/invoke.texi (-minstrument-return): Document.

gcc/testsuite/:

2018-11-29  Andi Kleen  <ak@linux.intel.com>

* gcc.target/i386/returninst1.c: New test.
* gcc.target/i386/returninst2.c: New test.
* gcc.target/i386/returninst3.c: New test.

From-SVN: r266652

gcc/ChangeLog
gcc/config/i386/i386-opts.h
gcc/config/i386/i386.c
gcc/config/i386/i386.opt
gcc/doc/invoke.texi
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/i386/returninst1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/returninst2.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/returninst3.c [new file with mode: 0644]

index d2e8b1f2d3e52c4b7d193825d08fc43378270373..9f19bc685ed8d0bbc02acd567e6fec20a0b9fabc 100644 (file)
@@ -1,3 +1,12 @@
+2018-11-29  Andi Kleen  <ak@linux.intel.com>
+
+       * config/i386/i386-opts.h (enum instrument_return): Add.
+       * config/i386/i386.c (output_return_instrumentation): Add.
+       (ix86_output_function_return): Call output_return_instrumentation.
+       (ix86_output_call_insn): Call output_return_instrumentation.
+       * config/i386/i386.opt: Add -minstrument-return=.
+       * doc/invoke.texi (-minstrument-return): Document.
+
 2018-11-29  Eric Botcazou  <ebotcazou@adacore.com>
 
        PR target/87807
index 46366cbfa725b55d36f5159cab3cfb8a037e0d3c..35e9413100e2585c098e321357ce348b7e67f64b 100644 (file)
@@ -119,4 +119,10 @@ enum indirect_branch {
   indirect_branch_thunk_extern
 };
 
+enum instrument_return {
+  instrument_return_none = 0,
+  instrument_return_call,
+  instrument_return_nop5
+};
+
 #endif
index 209b74aa4dca65d15ffe7943cfa3d387da07dced..98928d99265d0f7cd2519a2988eb36bc2a2208c8 100644 (file)
@@ -28385,12 +28385,47 @@ ix86_output_indirect_jmp (rtx call_op)
     return "%!jmp\t%A0";
 }
 
+/* Output return instrumentation for current function if needed.  */
+
+static void
+output_return_instrumentation (void)
+{
+  if (ix86_instrument_return != instrument_return_none
+      && flag_fentry
+      && !DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (cfun->decl))
+    {
+      if (ix86_flag_record_return)
+       fprintf (asm_out_file, "1:\n");
+      switch (ix86_instrument_return)
+       {
+       case instrument_return_call:
+         fprintf (asm_out_file, "\tcall\t__return__\n");
+         break;
+       case instrument_return_nop5:
+         /* 5 byte nop: nopl 0(%[re]ax,%[re]ax,1)  */
+         fprintf (asm_out_file, ASM_BYTE "0x0f, 0x1f, 0x44, 0x00, 0x00\n");
+         break;
+       case instrument_return_none:
+         break;
+       }
+
+      if (ix86_flag_record_return)
+       {
+         fprintf (asm_out_file, "\t.section __return_loc, \"a\",@progbits\n");
+         fprintf (asm_out_file, "\t.%s 1b\n", TARGET_64BIT ? "quad" : "long");
+         fprintf (asm_out_file, "\t.previous\n");
+       }
+    }
+}
+
 /* Output function return.  CALL_OP is the jump target.  Add a REP
    prefix to RET if LONG_P is true and function return is kept.  */
 
 const char *
 ix86_output_function_return (bool long_p)
 {
+  output_return_instrumentation ();
+
   if (cfun->machine->function_return_type != indirect_branch_keep)
     {
       char thunk_name[32];
@@ -28503,6 +28538,7 @@ ix86_output_call_insn (rtx_insn *insn, rtx call_op)
 
   if (SIBLING_CALL_P (insn))
     {
+      output_return_instrumentation ();
       if (direct_p)
        {
          if (ix86_nopic_noplt_attribute_p (call_op))
index 1705815a2ec586a86656140ac6662f81f96e4247..bacfabe378edcd0710dd2b3958b534fe486cc84f 100644 (file)
@@ -1067,3 +1067,24 @@ Support WAITPKG built-in functions and code generation.
 mcldemote
 Target Report Mask(ISA_CLDEMOTE) Var(ix86_isa_flags2) Save
 Support CLDEMOTE built-in functions and code generation.
+
+minstrument-return=
+Target Report RejectNegative Joined Enum(instrument_return) Var(ix86_instrument_return) Init(instrument_return_none)
+Instrument function exit in instrumented functions with __fentry__.
+
+Enum
+Name(instrument_return) Type(enum instrument_return)
+Known choices for return instrumentation with -minstrument-return=
+
+EnumValue
+Enum(instrument_return) String(none) Value(instrument_return_none)
+
+EnumValue
+Enum(instrument_return) String(call) Value(instrument_return_call)
+
+EnumValue
+Enum(instrument_return) String(nop5) Value(instrument_return_nop5)
+
+mrecord-return
+Target Report Var(ix86_flag_record_return) Init(0)
+Generate a __return_loc section pointing to all return instrumentation code.
index 6a694a695a1d0b962e7f06952cfed875948f2e98..d457980dbf74378364eb2f2736cb8435176b95ab 100644 (file)
@@ -1316,6 +1316,7 @@ See RS/6000 and PowerPC Options.
 -mcmodel=@var{code-model}  -mabi=@var{name}  -maddress-mode=@var{mode} @gol
 -m32  -m64  -mx32  -m16  -miamcu  -mlarge-data-threshold=@var{num} @gol
 -msse2avx  -mfentry  -mrecord-mcount  -mnop-mcount  -m8bit-idiv @gol
+-minstrument-return=@var{type} @gol
 -mavx256-split-unaligned-load  -mavx256-split-unaligned-store @gol
 -malign-data=@var{type}  -mstack-protector-guard=@var{guard} @gol
 -mstack-protector-guard-reg=@var{reg} @gol
@@ -29077,6 +29078,19 @@ the profiling functions as NOPs. This is useful when they
 should be patched in later dynamically. This is likely only
 useful together with @option{-mrecord-mcount}.
 
+@item -minstrument-return=@var{type}
+@opindex minstrument-return
+Instrument function exit in -pg -mfentry instrumented functions with
+call to specified function. This only instruments true returns ending
+with ret, but not sibling calls ending with jump. Valid types
+are @var{none} to not instrument, @var{call} to generate a call to __return__,
+or @var{nop5} to generate a 5 byte nop.
+
+@item -mrecord-return
+@itemx -mno-record-return
+@opindex mrecord-return
+Generate a __return_loc section pointing to all return instrumentation code.
+
 @item -mskip-rax-setup
 @itemx -mno-skip-rax-setup
 @opindex mskip-rax-setup
index d996dce7265aebbdc2c9dc3c3f8f61371c03816c..ebe2813c93fb45faa00959b4b392d6a56f9334d7 100644 (file)
@@ -1,3 +1,9 @@
+2018-11-29  Andi Kleen  <ak@linux.intel.com>
+
+       * gcc.target/i386/returninst1.c: New test.
+       * gcc.target/i386/returninst2.c: New test.
+       * gcc.target/i386/returninst3.c: New test.
+
 2018-11-29  Eric Botcazou  <ebotcazou@adacore.com>
 
        * gcc.target/sparc/20181129-1.c: New test.
diff --git a/gcc/testsuite/gcc.target/i386/returninst1.c b/gcc/testsuite/gcc.target/i386/returninst1.c
new file mode 100644 (file)
index 0000000..f970e75
--- /dev/null
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-pg -mfentry -minstrument-return=call -mrecord-return" } */
+/* { dg-final { scan-assembler "call.*__return__" } } */
+/* { dg-final { scan-assembler "section.*return_loc" } } */
+
+int func(int a)
+{
+  return a+1;
+}
+
+int func2(int a)
+{
+  return a+1;
+}
diff --git a/gcc/testsuite/gcc.target/i386/returninst2.c b/gcc/testsuite/gcc.target/i386/returninst2.c
new file mode 100644 (file)
index 0000000..716b385
--- /dev/null
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-pg -mfentry -minstrument-return=nop5 -mrecord-return" } */
+/* { dg-final { scan-assembler-times "0x0f, 0x1f, 0x44, 0x00, 0x00" 3 } } */
+/* { dg-final { scan-assembler "section.*return_loc" } } */
+
+int func(int a)
+{
+  return a+1;
+}
+
+int func2(int a)
+{
+  return a+1;
+}
+
+extern void func4(int);
+
+int func3(int a)
+{
+  func4(a + 1);
+}
diff --git a/gcc/testsuite/gcc.target/i386/returninst3.c b/gcc/testsuite/gcc.target/i386/returninst3.c
new file mode 100644 (file)
index 0000000..5bbc60e
--- /dev/null
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-pg -mfentry -minstrument-return=call" } */
+/* { dg-final { scan-assembler-not "call.*__return__" } } */
+
+__attribute__((no_instrument_function))
+int func(int a)
+{
+  return a+1;
+}