Squashed 'third_party/elfutils/' content from commit 555e15e

Change-Id: I61cde98949e47e5c8c09c33260de17f30921be79
git-subtree-dir: third_party/elfutils
git-subtree-split: 555e15ebe8bf1eb33d00747173cfc80cc65648a4
diff --git a/tests/backtrace-child.c b/tests/backtrace-child.c
new file mode 100644
index 0000000..2c27414
--- /dev/null
+++ b/tests/backtrace-child.c
@@ -0,0 +1,250 @@
+/* Test child for parent backtrace test.
+   Copyright (C) 2013, 2016 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file 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 of the License, or
+   (at your option) any later version.
+
+   elfutils 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 this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* Command line syntax: ./backtrace-child [--ptraceme|--gencore]
+   --ptraceme will call ptrace (PTRACE_TRACEME) in the two threads.
+   --gencore will call abort () at its end.
+   Main thread will signal SIGUSR2.  Other thread will signal SIGUSR1.
+   There used to be a difference between x86_64 and other architectures.
+   To test getting a signal at the very first instruction of a function:
+     PC will get changed to function 'jmp' by backtrace.c function
+     prepare_thread.  Then SIGUSR2 will be signalled to backtrace-child
+     which will invoke function sigusr2.
+     This is all done so that signal interrupts execution of the very first
+     instruction of a function.  Properly handled unwind should not slip into
+     the previous unrelated function.
+     The tested functionality is arch-independent but the code reproducing it
+     has to be arch-specific.
+   On non-x86_64:
+     sigusr2 gets called by normal function call from function stdarg.
+   On any arch then sigusr2 calls raise (SIGUSR1) for --ptraceme.
+   abort () is called otherwise, expected for --gencore core dump.
+
+   Expected x86_64 output:
+   TID 10276:
+   # 0 0x7f7ab61e9e6b      raise
+   # 1 0x7f7ab661af47 - 1  main
+   # 2 0x7f7ab5e3bb45 - 1  __libc_start_main
+   # 3 0x7f7ab661aa09 - 1  _start
+   TID 10278:
+   # 0 0x7f7ab61e9e6b      raise
+   # 1 0x7f7ab661ab3c - 1  sigusr2
+   # 2 0x7f7ab5e4fa60      __restore_rt
+   # 3 0x7f7ab661ab47      jmp
+   # 4 0x7f7ab661ac92 - 1  stdarg
+   # 5 0x7f7ab661acba - 1  backtracegen
+   # 6 0x7f7ab661acd1 - 1  start
+   # 7 0x7f7ab61e2c53 - 1  start_thread
+   # 8 0x7f7ab5f0fdbd - 1  __clone
+
+   Expected non-x86_64 (i386) output; __kernel_vsyscall are skipped if found:
+   TID 10408:
+   # 0 0xf779f430          __kernel_vsyscall
+   # 1 0xf7771466 - 1      raise
+   # 2 0xf77c1d07 - 1      main
+   # 3 0xf75bd963 - 1      __libc_start_main
+   # 4 0xf77c1761 - 1      _start
+   TID 10412:
+   # 0 0xf779f430          __kernel_vsyscall
+   # 1 0xf7771466 - 1      raise
+   # 2 0xf77c18f4 - 1      sigusr2
+   # 3 0xf77c1a10 - 1      stdarg
+   # 4 0xf77c1a2c - 1      backtracegen
+   # 5 0xf77c1a48 - 1      start
+   # 6 0xf77699da - 1      start_thread
+   # 7 0xf769bbfe - 1      __clone
+
+   But the raise jmp patching was unreliable. It depends on the CFI for the raise()
+   function in glibc to be the same as for the jmp() function. This is not always
+   the case. Some newer glibc versions rewrote raise() and now the CFA is calculated
+   differently. So we disable raise jmp patching everywhere.
+   */
+
+#ifdef __x86_64__
+/* #define RAISE_JMP_PATCHING 1 */
+#endif
+
+#include <config.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <errno.h>
+#include <string.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#ifndef __linux__
+
+int
+main (int argc __attribute__ ((unused)), char **argv)
+{
+  fprintf (stderr, "%s: Unwinding not supported for this architecture\n",
+           argv[0]);
+  return 77;
+}
+
+#else /* __linux__ */
+#include <sys/ptrace.h>
+
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
+#define NOINLINE_NOCLONE __attribute__ ((noinline, noclone))
+#else
+#define NOINLINE_NOCLONE __attribute__ ((noinline))
+#endif
+
+#define NORETURN __attribute__ ((noreturn))
+#define UNUSED __attribute__ ((unused))
+#define USED __attribute__ ((used))
+
+static int ptraceme, gencore;
+
+/* Execution will arrive here from jmp by an artificial ptrace-spawn signal.  */
+
+static NOINLINE_NOCLONE void
+sigusr2 (int signo)
+{
+  assert (signo == SIGUSR2);
+  if (! gencore)
+    {
+      raise (SIGUSR1);
+      /* Do not return as stack may be invalid due to ptrace-patched PC to the
+	 jmp function.  */
+      pthread_exit (NULL);
+      /* Not reached.  */
+      abort ();
+    }
+  /* Here we dump the core for --gencore.  */
+  raise (SIGABRT);
+  /* Avoid tail call optimization for the raise call.  */
+  asm volatile ("");
+}
+
+static NOINLINE_NOCLONE void
+dummy1 (void)
+{
+  asm volatile ("");
+}
+
+#ifdef RAISE_JMP_PATCHING
+static NOINLINE_NOCLONE USED void
+jmp (void)
+{
+  /* Not reached, signal will get ptrace-spawn to jump into sigusr2.  */
+  abort ();
+}
+#endif
+
+static NOINLINE_NOCLONE void
+dummy2 (void)
+{
+  asm volatile ("");
+}
+
+static NOINLINE_NOCLONE NORETURN void
+stdarg (int f UNUSED, ...)
+{
+  sighandler_t sigusr2_orig = signal (SIGUSR2, sigusr2);
+  assert (sigusr2_orig == SIG_DFL);
+  errno = 0;
+  if (ptraceme)
+    {
+      long l = ptrace (PTRACE_TRACEME, 0, NULL, NULL);
+      assert (errno == 0);
+      assert (l == 0);
+    }
+#ifdef RAISE_JMP_PATCHING
+  if (! gencore)
+    {
+      /* Execution will get PC patched into function jmp.  */
+      raise (SIGUSR1);
+    }
+#endif
+  sigusr2 (SIGUSR2);
+  /* Not reached.  */
+  abort ();
+}
+
+static NOINLINE_NOCLONE void
+dummy3 (void)
+{
+  asm volatile ("");
+}
+
+static NOINLINE_NOCLONE void
+backtracegen (void)
+{
+  stdarg (1);
+  /* Here should be no instruction after the stdarg call as it is noreturn
+     function.  It must be stdarg so that it is a call and not jump (jump as
+     a tail-call).  */
+}
+
+static NOINLINE_NOCLONE void
+dummy4 (void)
+{
+  asm volatile ("");
+}
+
+static void *
+start (void *arg UNUSED)
+{
+  backtracegen ();
+  /* Not reached.  */
+  abort ();
+}
+
+int
+main (int argc UNUSED, char **argv)
+{
+  setbuf (stdout, NULL);
+  assert (*argv++);
+  ptraceme = (*argv && strcmp (*argv, "--ptraceme") == 0);
+  argv += ptraceme;
+  gencore = (*argv && strcmp (*argv, "--gencore") == 0);
+  argv += gencore;
+  assert (!*argv);
+  /* These dummy* functions are there so that each of their surrounding
+     functions has some unrelated code around.  The purpose of some of the
+     tests is verify unwinding the very first / after the very last instruction
+     does not inappropriately slip into the unrelated code around.  */
+  dummy1 ();
+  dummy2 ();
+  dummy3 ();
+  dummy4 ();
+  if (gencore)
+    printf ("%ld\n", (long) getpid ());
+  pthread_t thread;
+  int i = pthread_create (&thread, NULL, start, NULL);
+  // pthread_* functions do not set errno.
+  assert (i == 0);
+  if (ptraceme)
+    {
+      errno = 0;
+      long l = ptrace (PTRACE_TRACEME, 0, NULL, NULL);
+      assert (errno == 0);
+      assert (l == 0);
+    }
+  if (gencore)
+    pthread_join (thread, NULL);
+  else
+    raise (SIGUSR2);
+  return 0;
+}
+
+#endif /* ! __linux__ */
+