Blame tests/backtrace.c

Packit Service 97d2fb
/* Test program for unwinding of frames.
Packit Service 97d2fb
   Copyright (C) 2013, 2014, 2016 Red Hat, Inc.
Packit Service 97d2fb
   This file is part of elfutils.
Packit Service 97d2fb
Packit Service 97d2fb
   This file is free software; you can redistribute it and/or modify
Packit Service 97d2fb
   it under the terms of the GNU General Public License as published by
Packit Service 97d2fb
   the Free Software Foundation; either version 3 of the License, or
Packit Service 97d2fb
   (at your option) any later version.
Packit Service 97d2fb
Packit Service 97d2fb
   elfutils is distributed in the hope that it will be useful, but
Packit Service 97d2fb
   WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 97d2fb
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service 97d2fb
   GNU General Public License for more details.
Packit Service 97d2fb
Packit Service 97d2fb
   You should have received a copy of the GNU General Public License
Packit Service 97d2fb
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
Packit Service 97d2fb
Packit Service 97d2fb
#include <config.h>
Packit Service 97d2fb
#include <assert.h>
Packit Service 97d2fb
#include <inttypes.h>
Packit Service 97d2fb
#include <stdio.h>
Packit Service 97d2fb
#include <stdio_ext.h>
Packit Service 97d2fb
#include <locale.h>
Packit Service 97d2fb
#include <dirent.h>
Packit Service 97d2fb
#include <stdlib.h>
Packit Service 97d2fb
#include <errno.h>
Packit Service 97d2fb
#include <unistd.h>
Packit Service 97d2fb
#include <dwarf.h>
Packit Service 97d2fb
#ifdef __linux__
Packit Service 97d2fb
#include <sys/resource.h>
Packit Service 97d2fb
#include <sys/ptrace.h>
Packit Service 97d2fb
#include <signal.h>
Packit Service 97d2fb
#include <sys/types.h>
Packit Service 97d2fb
#include <sys/wait.h>
Packit Service 97d2fb
#include <sys/user.h>
Packit Service 97d2fb
#include <fcntl.h>
Packit Service 97d2fb
#include <string.h>
Packit Service 97d2fb
#include <argp.h>
Packit Service 97d2fb
#include ELFUTILS_HEADER(dwfl)
Packit Service 97d2fb
#endif
Packit Service 97d2fb
#include "system.h"
Packit Service 97d2fb
Packit Service 97d2fb
#ifndef __linux__
Packit Service 97d2fb
Packit Service 97d2fb
int
Packit Service 97d2fb
main (int argc __attribute__ ((unused)), char **argv)
Packit Service 97d2fb
{
Packit Service 97d2fb
  fprintf (stderr, "%s: Unwinding not supported for this architecture\n",
Packit Service 97d2fb
	   argv[0]);
Packit Service 97d2fb
  return 77;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
#else /* __linux__ */
Packit Service 97d2fb
Packit Service 97d2fb
static int
Packit Service 97d2fb
dump_modules (Dwfl_Module *mod, void **userdata __attribute__ ((unused)),
Packit Service 97d2fb
	      const char *name, Dwarf_Addr start,
Packit Service 97d2fb
	      void *arg __attribute__ ((unused)))
Packit Service 97d2fb
{
Packit Service 97d2fb
  Dwarf_Addr end;
Packit Service 97d2fb
  dwfl_module_info (mod, NULL, NULL, &end, NULL, NULL, NULL, NULL);
Packit Service 97d2fb
  printf ("%#" PRIx64 "\t%#" PRIx64 "\t%s\n", (uint64_t) start, (uint64_t) end,
Packit Service 97d2fb
	  name);
Packit Service 97d2fb
  return DWARF_CB_OK;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static bool use_raise_jmp_patching;
Packit Service 97d2fb
static pid_t check_tid;
Packit Service 97d2fb
Packit Service 97d2fb
static void
Packit Service 97d2fb
callback_verify (pid_t tid, unsigned frameno, Dwarf_Addr pc,
Packit Service 97d2fb
		 const char *symname, Dwfl *dwfl)
Packit Service 97d2fb
{
Packit Service 97d2fb
  static bool seen_main = false;
Packit Service 97d2fb
  if (symname && *symname == '.')
Packit Service 97d2fb
    symname++;
Packit Service 97d2fb
  if (symname && strcmp (symname, "main") == 0)
Packit Service 97d2fb
    seen_main = true;
Packit Service 97d2fb
  if (pc == 0)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      assert (seen_main);
Packit Service 97d2fb
      return;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  if (check_tid == 0)
Packit Service 97d2fb
    check_tid = tid;
Packit Service 97d2fb
  if (tid != check_tid)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      // For the main thread we are only interested if we can unwind till
Packit Service 97d2fb
      // we see the "main" symbol.
Packit Service 97d2fb
      return;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  Dwfl_Module *mod;
Packit Service 97d2fb
  /* See case 4. Special case to help out simple frame pointer unwinders. */
Packit Service 97d2fb
  static bool duplicate_sigusr2 = false;
Packit Service 97d2fb
  if (duplicate_sigusr2)
Packit Service 97d2fb
    frameno--;
Packit Service 97d2fb
  static bool reduce_frameno = false;
Packit Service 97d2fb
  if (reduce_frameno)
Packit Service 97d2fb
    frameno--;
Packit Service 97d2fb
  if (! use_raise_jmp_patching && frameno >= 2)
Packit Service 97d2fb
    frameno += 2;
Packit Service 97d2fb
  const char *symname2 = NULL;
Packit Service 97d2fb
  switch (frameno)
Packit Service 97d2fb
  {
Packit Service 97d2fb
    case 0:
Packit Service 97d2fb
      if (! reduce_frameno && symname
Packit Service 97d2fb
	       && (strcmp (symname, "__kernel_vsyscall") == 0
Packit Service 97d2fb
		   || strcmp (symname, "__libc_do_syscall") == 0))
Packit Service 97d2fb
	reduce_frameno = true;
Packit Service 97d2fb
      else
Packit Service 97d2fb
	assert (symname && strcmp (symname, "raise") == 0);
Packit Service 97d2fb
      break;
Packit Service 97d2fb
    case 1:
Packit Service 97d2fb
      assert (symname != NULL && strcmp (symname, "sigusr2") == 0);
Packit Service 97d2fb
      break;
Packit Service 97d2fb
    case 2: // x86_64 only
Packit Service 97d2fb
      /* __restore_rt - glibc maybe does not have to have this symbol.  */
Packit Service 97d2fb
      break;
Packit Service 97d2fb
    case 3: // use_raise_jmp_patching
Packit Service 97d2fb
      if (use_raise_jmp_patching)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* Verify we trapped on the very first instruction of jmp.  */
Packit Service 97d2fb
	  assert (symname != NULL && strcmp (symname, "jmp") == 0);
Packit Service 97d2fb
	  mod = dwfl_addrmodule (dwfl, pc - 1);
Packit Service 97d2fb
	  if (mod)
Packit Service 97d2fb
	    symname2 = dwfl_module_addrname (mod, pc - 1);
Packit Service 97d2fb
	  assert (symname2 == NULL || strcmp (symname2, "jmp") != 0);
Packit Service 97d2fb
	  break;
Packit Service 97d2fb
	}
Packit Service 97d2fb
      FALLTHROUGH;
Packit Service 97d2fb
    case 4:
Packit Service 97d2fb
      /* Some simple frame unwinders get this wrong and think sigusr2
Packit Service 97d2fb
	 is calling itself again. Allow it and just pretend there is
Packit Service 97d2fb
	 an extra sigusr2 frame. */
Packit Service 97d2fb
      if (symname != NULL && strcmp (symname, "sigusr2") == 0)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  duplicate_sigusr2 = true;
Packit Service 97d2fb
	  break;
Packit Service 97d2fb
	}
Packit Service 97d2fb
      assert (symname != NULL && strcmp (symname, "stdarg") == 0);
Packit Service 97d2fb
      break;
Packit Service 97d2fb
    case 5:
Packit Service 97d2fb
      /* Verify we trapped on the very last instruction of child.  */
Packit Service 97d2fb
      assert (symname != NULL && strcmp (symname, "backtracegen") == 0);
Packit Service 97d2fb
      mod = dwfl_addrmodule (dwfl, pc);
Packit Service 97d2fb
      if (mod)
Packit Service 97d2fb
	symname2 = dwfl_module_addrname (mod, pc);
Packit Service 97d2fb
Packit Service 97d2fb
      // Note that the following assert might in theory even fail on x86_64,
Packit Service 97d2fb
      // there is no guarantee that the compiler doesn't reorder the
Packit Service 97d2fb
      // instructions or even inserts some padding instructions at the end
Packit Service 97d2fb
      // (which apparently happens on ppc64).
Packit Service 97d2fb
      if (use_raise_jmp_patching)
Packit Service 97d2fb
        assert (symname2 == NULL || strcmp (symname2, "backtracegen") != 0);
Packit Service 97d2fb
      break;
Packit Service 97d2fb
  }
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static int
Packit Service 97d2fb
frame_callback (Dwfl_Frame *state, void *frame_arg)
Packit Service 97d2fb
{
Packit Service 97d2fb
  int *framenop = frame_arg;
Packit Service 97d2fb
  Dwarf_Addr pc;
Packit Service 97d2fb
  bool isactivation;
Packit Service 97d2fb
Packit Service 97d2fb
  if (*framenop > 16)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      error (0, 0, "Too many frames: %d\n", *framenop);
Packit Service 97d2fb
      return DWARF_CB_ABORT;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  if (! dwfl_frame_pc (state, &pc, &isactivation))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      error (0, 0, "%s", dwfl_errmsg (-1));
Packit Service 97d2fb
      return DWARF_CB_ABORT;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  Dwarf_Addr pc_adjusted = pc - (isactivation ? 0 : 1);
Packit Service 97d2fb
Packit Service 97d2fb
  /* Get PC->SYMNAME.  */
Packit Service 97d2fb
  Dwfl_Thread *thread = dwfl_frame_thread (state);
Packit Service 97d2fb
  Dwfl *dwfl = dwfl_thread_dwfl (thread);
Packit Service 97d2fb
  Dwfl_Module *mod = dwfl_addrmodule (dwfl, pc_adjusted);
Packit Service 97d2fb
  const char *symname = NULL;
Packit Service 97d2fb
  if (mod)
Packit Service 97d2fb
    symname = dwfl_module_addrname (mod, pc_adjusted);
Packit Service 97d2fb
Packit Service 97d2fb
  printf ("#%2d %#" PRIx64 "%4s\t%s\n", *framenop, (uint64_t) pc,
Packit Service 97d2fb
	  ! isactivation ? "- 1" : "", symname ?: "<null>");
Packit Service 97d2fb
  pid_t tid = dwfl_thread_tid (thread);
Packit Service 97d2fb
  callback_verify (tid, *framenop, pc, symname, dwfl);
Packit Service 97d2fb
  (*framenop)++;
Packit Service 97d2fb
Packit Service 97d2fb
  return DWARF_CB_OK;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static int
Packit Service 97d2fb
thread_callback (Dwfl_Thread *thread, void *thread_arg __attribute__((unused)))
Packit Service 97d2fb
{
Packit Service 97d2fb
  printf ("TID %ld:\n", (long) dwfl_thread_tid (thread));
Packit Service 97d2fb
  int frameno = 0;
Packit Service 97d2fb
  switch (dwfl_thread_getframes (thread, frame_callback, &frameno))
Packit Service 97d2fb
    {
Packit Service 97d2fb
    case 0:
Packit Service 97d2fb
      break;
Packit Service 97d2fb
    case DWARF_CB_ABORT:
Packit Service 97d2fb
      return DWARF_CB_ABORT;
Packit Service 97d2fb
    case -1:
Packit Service 97d2fb
      error (0, 0, "dwfl_thread_getframes: %s", dwfl_errmsg (-1));
Packit Service 97d2fb
      /* All platforms do not have yet proper unwind termination.  */
Packit Service 97d2fb
      break;
Packit Service 97d2fb
    default:
Packit Service 97d2fb
      abort ();
Packit Service 97d2fb
    }
Packit Service 97d2fb
  return DWARF_CB_OK;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static void
Packit Service 97d2fb
dump (Dwfl *dwfl)
Packit Service 97d2fb
{
Packit Service 97d2fb
  ptrdiff_t ptrdiff = dwfl_getmodules (dwfl, dump_modules, NULL, 0);
Packit Service 97d2fb
  assert (ptrdiff == 0);
Packit Service 97d2fb
  bool err = false;
Packit Service 97d2fb
  switch (dwfl_getthreads (dwfl, thread_callback, NULL))
Packit Service 97d2fb
    {
Packit Service 97d2fb
    case 0:
Packit Service 97d2fb
      break;
Packit Service 97d2fb
    case DWARF_CB_ABORT:
Packit Service 97d2fb
      err = true;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
    case -1:
Packit Service 97d2fb
      error (0, 0, "dwfl_getthreads: %s", dwfl_errmsg (-1));
Packit Service 97d2fb
      err = true;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
    default:
Packit Service 97d2fb
      abort ();
Packit Service 97d2fb
    }
Packit Service 97d2fb
  callback_verify (0, 0, 0, NULL, dwfl);
Packit Service 97d2fb
  if (err)
Packit Service 97d2fb
    exit (EXIT_FAILURE);
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
struct see_exec_module
Packit Service 97d2fb
{
Packit Service 97d2fb
  Dwfl_Module *mod;
Packit Service 97d2fb
  char selfpath[PATH_MAX + 1];
Packit Service 97d2fb
};
Packit Service 97d2fb
Packit Service 97d2fb
static int
Packit Service 97d2fb
see_exec_module (Dwfl_Module *mod, void **userdata __attribute__ ((unused)),
Packit Service 97d2fb
		 const char *name __attribute__ ((unused)),
Packit Service 97d2fb
		 Dwarf_Addr start __attribute__ ((unused)), void *arg)
Packit Service 97d2fb
{
Packit Service 97d2fb
  struct see_exec_module *data = arg;
Packit Service 97d2fb
  if (strcmp (name, data->selfpath) != 0)
Packit Service 97d2fb
    return DWARF_CB_OK;
Packit Service 97d2fb
  assert (data->mod == NULL);
Packit Service 97d2fb
  data->mod = mod;
Packit Service 97d2fb
  return DWARF_CB_ABORT;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* We used to do this on x86_64 only (see backtrace-child why we now don't):
Packit Service 97d2fb
     PC will get changed to function 'jmp' by backtrace.c function
Packit Service 97d2fb
     prepare_thread.  Then SIGUSR2 will be signalled to backtrace-child
Packit Service 97d2fb
     which will invoke function sigusr2.
Packit Service 97d2fb
     This is all done so that signal interrupts execution of the very first
Packit Service 97d2fb
     instruction of a function.  Properly handled unwind should not slip into
Packit Service 97d2fb
     the previous unrelated function.  */
Packit Service 97d2fb
Packit Service 97d2fb
#ifdef __x86_64__
Packit Service 97d2fb
/* #define RAISE_JMP_PATCHING 1 */
Packit Service 97d2fb
#endif
Packit Service 97d2fb
Packit Service 97d2fb
static void
Packit Service 97d2fb
prepare_thread (pid_t pid2 __attribute__ ((unused)),
Packit Service 97d2fb
		void (*jmp) (void) __attribute__ ((unused)))
Packit Service 97d2fb
{
Packit Service 97d2fb
#ifndef RAISE_JMP_PATCHING
Packit Service 97d2fb
  abort ();
Packit Service 97d2fb
#else /* RAISE_JMP_PATCHING */
Packit Service 97d2fb
  long l;
Packit Service 97d2fb
  struct user_regs_struct user_regs;
Packit Service 97d2fb
  errno = 0;
Packit Service 97d2fb
  l = ptrace (PTRACE_GETREGS, pid2, 0, (intptr_t) &user_regs);
Packit Service 97d2fb
  assert (l == 0);
Packit Service 97d2fb
  user_regs.rip = (intptr_t) jmp;
Packit Service 97d2fb
  l = ptrace (PTRACE_SETREGS, pid2, 0, (intptr_t) &user_regs);
Packit Service 97d2fb
  assert (l == 0);
Packit Service 97d2fb
  l = ptrace (PTRACE_CONT, pid2, NULL, (void *) (intptr_t) SIGUSR2);
Packit Service 97d2fb
  int status;
Packit Service 97d2fb
  pid_t got = waitpid (pid2, &status, __WALL);
Packit Service 97d2fb
  assert (got == pid2);
Packit Service 97d2fb
  assert (WIFSTOPPED (status));
Packit Service 97d2fb
  assert (WSTOPSIG (status) == SIGUSR1);
Packit Service 97d2fb
#endif /* RAISE_JMP_PATCHING */
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
#include <asm/unistd.h>
Packit Service 97d2fb
#include <unistd.h>
Packit Service 97d2fb
Packit Service 97d2fb
static void
Packit Service 97d2fb
report_pid (Dwfl *dwfl, pid_t pid)
Packit Service 97d2fb
{
Packit Service 97d2fb
  int result = dwfl_linux_proc_report (dwfl, pid);
Packit Service 97d2fb
  if (result < 0)
Packit Service 97d2fb
    error (2, 0, "dwfl_linux_proc_report: %s", dwfl_errmsg (-1));
Packit Service 97d2fb
  else if (result > 0)
Packit Service 97d2fb
    error (2, result, "dwfl_linux_proc_report");
Packit Service 97d2fb
Packit Service 97d2fb
  if (dwfl_report_end (dwfl, NULL, NULL) != 0)
Packit Service 97d2fb
    error (2, 0, "dwfl_report_end: %s", dwfl_errmsg (-1));
Packit Service 97d2fb
Packit Service 97d2fb
  result = dwfl_linux_proc_attach (dwfl, pid, true);
Packit Service 97d2fb
  if (result < 0)
Packit Service 97d2fb
    error (2, 0, "dwfl_linux_proc_attach: %s", dwfl_errmsg (-1));
Packit Service 97d2fb
  else if (result > 0)
Packit Service 97d2fb
    error (2, result, "dwfl_linux_proc_attach");
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static Dwfl *
Packit Service 97d2fb
pid_to_dwfl (pid_t pid)
Packit Service 97d2fb
{
Packit Service 97d2fb
  static char *debuginfo_path;
Packit Service 97d2fb
  static const Dwfl_Callbacks proc_callbacks =
Packit Service 97d2fb
    {
Packit Service 97d2fb
      .find_debuginfo = dwfl_standard_find_debuginfo,
Packit Service 97d2fb
      .debuginfo_path = &debuginfo_path,
Packit Service 97d2fb
Packit Service 97d2fb
      .find_elf = dwfl_linux_proc_find_elf,
Packit Service 97d2fb
    };
Packit Service 97d2fb
  Dwfl *dwfl = dwfl_begin (&proc_callbacks);
Packit Service 97d2fb
  if (dwfl == NULL)
Packit Service 97d2fb
    error (2, 0, "dwfl_begin: %s", dwfl_errmsg (-1));
Packit Service 97d2fb
  report_pid (dwfl, pid);
Packit Service 97d2fb
  return dwfl;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static void
Packit Service 97d2fb
exec_dump (const char *exec)
Packit Service 97d2fb
{
Packit Service 97d2fb
  pid_t pid = fork ();
Packit Service 97d2fb
  switch (pid)
Packit Service 97d2fb
  {
Packit Service 97d2fb
    case -1:
Packit Service 97d2fb
      abort ();
Packit Service 97d2fb
    case 0:
Packit Service 97d2fb
      execl (exec, exec, "--ptraceme", NULL);
Packit Service 97d2fb
      abort ();
Packit Service 97d2fb
    default:
Packit Service 97d2fb
      break;
Packit Service 97d2fb
  }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Catch the main thread.  Catch it first otherwise the /proc evaluation of
Packit Service 97d2fb
     PID may have caught still ourselves before executing execl above.  */
Packit Service 97d2fb
  errno = 0;
Packit Service 97d2fb
  int status;
Packit Service 97d2fb
  pid_t got = waitpid (pid, &status, 0);
Packit Service 97d2fb
  assert (got == pid);
Packit Service 97d2fb
  assert (WIFSTOPPED (status));
Packit Service 97d2fb
  // Main thread will signal SIGUSR2.  Other thread will signal SIGUSR1.
Packit Service 97d2fb
  assert (WSTOPSIG (status) == SIGUSR2);
Packit Service 97d2fb
Packit Service 97d2fb
  /* Catch the spawned thread.  Do not use __WCLONE as we could get racy
Packit Service 97d2fb
     __WCLONE, probably despite pthread_create already had to be called the new
Packit Service 97d2fb
     task is not yet alive enough for waitpid.  */
Packit Service 97d2fb
  pid_t pid2 = waitpid (-1, &status, __WALL);
Packit Service 97d2fb
  assert (pid2 > 0);
Packit Service 97d2fb
  assert (pid2 != pid);
Packit Service 97d2fb
  assert (WIFSTOPPED (status));
Packit Service 97d2fb
  // Main thread will signal SIGUSR2.  Other thread will signal SIGUSR1.
Packit Service 97d2fb
  assert (WSTOPSIG (status) == SIGUSR1);
Packit Service 97d2fb
Packit Service 97d2fb
  Dwfl *dwfl = pid_to_dwfl (pid);
Packit Service 97d2fb
  char *selfpathname;
Packit Service 97d2fb
  int i = asprintf (&selfpathname, "/proc/%ld/exe", (long) pid);
Packit Service 97d2fb
  assert (i > 0);
Packit Service 97d2fb
  struct see_exec_module data;
Packit Service 97d2fb
  ssize_t ssize = readlink (selfpathname, data.selfpath,
Packit Service 97d2fb
			    sizeof (data.selfpath));
Packit Service 97d2fb
  free (selfpathname);
Packit Service 97d2fb
  assert (ssize > 0 && ssize < (ssize_t) sizeof (data.selfpath));
Packit Service 97d2fb
  data.selfpath[ssize] = '\0';
Packit Service 97d2fb
  data.mod = NULL;
Packit Service 97d2fb
  dwfl_getmodules (dwfl, see_exec_module, &data, 0);
Packit Service 97d2fb
  assert (data.mod != NULL);
Packit Service 97d2fb
  GElf_Addr loadbase;
Packit Service 97d2fb
  Elf *elf = dwfl_module_getelf (data.mod, &loadbase);
Packit Service 97d2fb
  GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (elf, &ehdr_mem);
Packit Service 97d2fb
  assert (ehdr != NULL);
Packit Service 97d2fb
  /* It is false also on x86_64 with i386 inferior.  */
Packit Service 97d2fb
#ifndef RAISE_JMP_PATCHING
Packit Service 97d2fb
  use_raise_jmp_patching = false;
Packit Service 97d2fb
#else /* RAISE_JMP_PATCHING_ */
Packit Service 97d2fb
  use_raise_jmp_patching = ehdr->e_machine == EM_X86_64;
Packit Service 97d2fb
#endif /* __x86_64__ */
Packit Service 97d2fb
  void (*jmp) (void) = 0;
Packit Service 97d2fb
  if (use_raise_jmp_patching)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      // Find inferior symbol named "jmp".
Packit Service 97d2fb
      int nsym = dwfl_module_getsymtab (data.mod);
Packit Service 97d2fb
      int symi;
Packit Service 97d2fb
      for (symi = 1; symi < nsym; ++symi)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  GElf_Sym symbol;
Packit Service 97d2fb
	  const char *symbol_name = dwfl_module_getsym (data.mod, symi, &symbol, NULL);
Packit Service 97d2fb
	  if (symbol_name == NULL)
Packit Service 97d2fb
	    continue;
Packit Service 97d2fb
	  switch (GELF_ST_TYPE (symbol.st_info))
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	    case STT_SECTION:
Packit Service 97d2fb
	    case STT_FILE:
Packit Service 97d2fb
	    case STT_TLS:
Packit Service 97d2fb
	      continue;
Packit Service 97d2fb
	    default:
Packit Service 97d2fb
	      if (strcmp (symbol_name, "jmp") != 0)
Packit Service 97d2fb
		continue;
Packit Service 97d2fb
	      break;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	  /* LOADBASE is already applied here.  */
Packit Service 97d2fb
	  jmp = (void (*) (void)) (uintptr_t) symbol.st_value;
Packit Service 97d2fb
	  break;
Packit Service 97d2fb
	}
Packit Service 97d2fb
      assert (symi < nsym);
Packit Service 97d2fb
      prepare_thread (pid2, jmp);
Packit Service 97d2fb
    }
Packit Service 97d2fb
  dwfl_end (dwfl);
Packit Service 97d2fb
  check_tid = pid2;
Packit Service 97d2fb
  dwfl = pid_to_dwfl (pid);
Packit Service 97d2fb
  dump (dwfl);
Packit Service 97d2fb
  dwfl_end (dwfl);
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
#define OPT_BACKTRACE_EXEC 0x100
Packit Service 97d2fb
Packit Service 97d2fb
static const struct argp_option options[] =
Packit Service 97d2fb
  {
Packit Service 97d2fb
    { "backtrace-exec", OPT_BACKTRACE_EXEC, "EXEC", 0, N_("Run executable"), 0 },
Packit Service 97d2fb
    { NULL, 0, NULL, 0, NULL, 0 }
Packit Service 97d2fb
  };
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
static error_t
Packit Service 97d2fb
parse_opt (int key, char *arg, struct argp_state *state)
Packit Service 97d2fb
{
Packit Service 97d2fb
  switch (key)
Packit Service 97d2fb
    {
Packit Service 97d2fb
    case ARGP_KEY_INIT:
Packit Service 97d2fb
      state->child_inputs[0] = state->input;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case OPT_BACKTRACE_EXEC:
Packit Service 97d2fb
      exec_dump (arg);
Packit Service 97d2fb
      exit (0);
Packit Service 97d2fb
Packit Service 97d2fb
    default:
Packit Service 97d2fb
      return ARGP_ERR_UNKNOWN;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  return 0;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
int
Packit Service 97d2fb
main (int argc __attribute__ ((unused)), char **argv)
Packit Service 97d2fb
{
Packit Service 97d2fb
  /* We use no threads here which can interfere with handling a stream.  */
Packit Service 97d2fb
  __fsetlocking (stdin, FSETLOCKING_BYCALLER);
Packit Service 97d2fb
  __fsetlocking (stdout, FSETLOCKING_BYCALLER);
Packit Service 97d2fb
  __fsetlocking (stderr, FSETLOCKING_BYCALLER);
Packit Service 97d2fb
Packit Service 97d2fb
  /* Set locale.  */
Packit Service 97d2fb
  (void) setlocale (LC_ALL, "");
Packit Service 97d2fb
Packit Service 97d2fb
  elf_version (EV_CURRENT);
Packit Service 97d2fb
Packit Service 97d2fb
  Dwfl *dwfl = NULL;
Packit Service 97d2fb
  const struct argp_child argp_children[] =
Packit Service 97d2fb
    {
Packit Service 97d2fb
      { .argp = dwfl_standard_argp () },
Packit Service 97d2fb
      { .argp = NULL }
Packit Service 97d2fb
    };
Packit Service 97d2fb
  const struct argp argp =
Packit Service 97d2fb
    {
Packit Service 97d2fb
      options, parse_opt, NULL, NULL, argp_children, NULL, NULL
Packit Service 97d2fb
    };
Packit Service 97d2fb
  (void) argp_parse (&argp, argc, argv, 0, NULL, &dwfl);
Packit Service 97d2fb
  assert (dwfl != NULL);
Packit Service 97d2fb
  /* We want to make sure the dwfl was properly attached.  */
Packit Service 97d2fb
  if (dwfl_pid (dwfl) < 0)
Packit Service 97d2fb
    error (2, 0, "dwfl_pid: %s", dwfl_errmsg (-1));
Packit Service 97d2fb
  dump (dwfl);
Packit Service 97d2fb
  dwfl_end (dwfl);
Packit Service 97d2fb
  return 0;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
#endif /* ! __linux__ */
Packit Service 97d2fb