Blame libdwfl/linux-pid-attach.c

Packit Service 97d2fb
/* Get Dwarf Frame state for target live PID process.
Packit Service 97d2fb
   Copyright (C) 2013, 2014, 2015, 2018 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 either
Packit Service 97d2fb
Packit Service 97d2fb
     * the GNU Lesser General Public License as published by the Free
Packit Service 97d2fb
       Software Foundation; either version 3 of the License, or (at
Packit Service 97d2fb
       your option) any later version
Packit Service 97d2fb
Packit Service 97d2fb
   or
Packit Service 97d2fb
Packit Service 97d2fb
     * the GNU General Public License as published by the Free
Packit Service 97d2fb
       Software Foundation; either version 2 of the License, or (at
Packit Service 97d2fb
       your option) any later version
Packit Service 97d2fb
Packit Service 97d2fb
   or both in parallel, as here.
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 GNU
Packit Service 97d2fb
   General Public License for more details.
Packit Service 97d2fb
Packit Service 97d2fb
   You should have received copies of the GNU General Public License and
Packit Service 97d2fb
   the GNU Lesser General Public License along with this program.  If
Packit Service 97d2fb
   not, see <http://www.gnu.org/licenses/>.  */
Packit Service 97d2fb
Packit Service 97d2fb
#ifdef HAVE_CONFIG_H
Packit Service 97d2fb
# include <config.h>
Packit Service 97d2fb
#endif
Packit Service 97d2fb
Packit Service 97d2fb
#include "libelfP.h"
Packit Service 97d2fb
#include "libdwflP.h"
Packit Service 97d2fb
#include <sys/types.h>
Packit Service 97d2fb
#include <sys/stat.h>
Packit Service 97d2fb
#include <fcntl.h>
Packit Service 97d2fb
#include <dirent.h>
Packit Service 97d2fb
#include <unistd.h>
Packit Service 97d2fb
Packit Service 97d2fb
#ifdef __linux__
Packit Service 97d2fb
Packit Service 97d2fb
#include <sys/uio.h>
Packit Service 97d2fb
#include <sys/ptrace.h>
Packit Service 97d2fb
#include <sys/syscall.h>
Packit Service 97d2fb
#include <sys/wait.h>
Packit Service 97d2fb
Packit Service 97d2fb
static bool
Packit Service 97d2fb
linux_proc_pid_is_stopped (pid_t pid)
Packit Service 97d2fb
{
Packit Service 97d2fb
  char buffer[64];
Packit Service 97d2fb
  FILE *procfile;
Packit Service 97d2fb
  bool retval, have_state;
Packit Service 97d2fb
Packit Service 97d2fb
  snprintf (buffer, sizeof (buffer), "/proc/%ld/status", (long) pid);
Packit Service 97d2fb
  procfile = fopen (buffer, "r");
Packit Service 97d2fb
  if (procfile == NULL)
Packit Service 97d2fb
    return false;
Packit Service 97d2fb
Packit Service 97d2fb
  have_state = false;
Packit Service 97d2fb
  while (fgets (buffer, sizeof (buffer), procfile) != NULL)
Packit Service 97d2fb
    if (strncmp (buffer, "State:", 6) == 0)
Packit Service 97d2fb
      {
Packit Service 97d2fb
	have_state = true;
Packit Service 97d2fb
	break;
Packit Service 97d2fb
      }
Packit Service 97d2fb
  retval = (have_state && strstr (buffer, "T (stopped)") != NULL);
Packit Service 97d2fb
  fclose (procfile);
Packit Service 97d2fb
  return retval;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
bool
Packit Service 97d2fb
internal_function
Packit Service 97d2fb
__libdwfl_ptrace_attach (pid_t tid, bool *tid_was_stoppedp)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (ptrace (PTRACE_ATTACH, tid, NULL, NULL) != 0)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      __libdwfl_seterrno (DWFL_E_ERRNO);
Packit Service 97d2fb
      return false;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  *tid_was_stoppedp = linux_proc_pid_is_stopped (tid);
Packit Service 97d2fb
  if (*tid_was_stoppedp)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* Make sure there is a SIGSTOP signal pending even when the process is
Packit Service 97d2fb
	 already State: T (stopped).  Older kernels might fail to generate
Packit Service 97d2fb
	 a SIGSTOP notification in that case in response to our PTRACE_ATTACH
Packit Service 97d2fb
	 above.  Which would make the waitpid below wait forever.  So emulate
Packit Service 97d2fb
	 it.  Since there can only be one SIGSTOP notification pending this is
Packit Service 97d2fb
	 safe.  See also gdb/linux-nat.c linux_nat_post_attach_wait.  */
Packit Service 97d2fb
      syscall (__NR_tkill, tid, SIGSTOP);
Packit Service 97d2fb
      ptrace (PTRACE_CONT, tid, NULL, NULL);
Packit Service 97d2fb
    }
Packit Service 97d2fb
  for (;;)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      int status;
Packit Service 97d2fb
      if (waitpid (tid, &status, __WALL) != tid || !WIFSTOPPED (status))
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  int saved_errno = errno;
Packit Service 97d2fb
	  ptrace (PTRACE_DETACH, tid, NULL, NULL);
Packit Service 97d2fb
	  errno = saved_errno;
Packit Service 97d2fb
	  __libdwfl_seterrno (DWFL_E_ERRNO);
Packit Service 97d2fb
	  return false;
Packit Service 97d2fb
	}
Packit Service 97d2fb
      if (WSTOPSIG (status) == SIGSTOP)
Packit Service 97d2fb
	break;
Packit Service 97d2fb
      if (ptrace (PTRACE_CONT, tid, NULL,
Packit Service 97d2fb
		  (void *) (uintptr_t) WSTOPSIG (status)) != 0)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  int saved_errno = errno;
Packit Service 97d2fb
	  ptrace (PTRACE_DETACH, tid, NULL, NULL);
Packit Service 97d2fb
	  errno = saved_errno;
Packit Service 97d2fb
	  __libdwfl_seterrno (DWFL_E_ERRNO);
Packit Service 97d2fb
	  return false;
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
  return true;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
#ifdef HAVE_PROCESS_VM_READV
Packit Service 97d2fb
/* Note that the result word size depends on the architecture word size.
Packit Service 97d2fb
   That is sizeof long. */
Packit Service 97d2fb
static bool
Packit Service 97d2fb
read_cached_memory (struct __libdwfl_pid_arg *pid_arg,
Packit Service 97d2fb
		    Dwarf_Addr addr, Dwarf_Word *result)
Packit Service 97d2fb
{
Packit Service 97d2fb
  /* Let the ptrace fallback deal with the corner case of the address
Packit Service 97d2fb
     possibly crossing a page boundery.  */
Packit Service 97d2fb
  if ((addr & ((Dwarf_Addr)__LIBDWFL_REMOTE_MEM_CACHE_SIZE - 1))
Packit Service 97d2fb
      > (Dwarf_Addr)__LIBDWFL_REMOTE_MEM_CACHE_SIZE - sizeof (unsigned long))
Packit Service 97d2fb
    return false;
Packit Service 97d2fb
Packit Service 97d2fb
  struct __libdwfl_remote_mem_cache *mem_cache = pid_arg->mem_cache;
Packit Service 97d2fb
  if (mem_cache == NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      size_t mem_cache_size = sizeof (struct __libdwfl_remote_mem_cache);
Packit Service 97d2fb
      mem_cache = (struct __libdwfl_remote_mem_cache *) malloc (mem_cache_size);
Packit Service 97d2fb
      if (mem_cache == NULL)
Packit Service 97d2fb
	return false;
Packit Service 97d2fb
Packit Service 97d2fb
      mem_cache->addr = 0;
Packit Service 97d2fb
      mem_cache->len = 0;
Packit Service 97d2fb
      pid_arg->mem_cache = mem_cache;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  unsigned char *d;
Packit Service 97d2fb
  if (addr >= mem_cache->addr && addr - mem_cache->addr < mem_cache->len)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      d = &mem_cache->buf[addr - mem_cache->addr];
Packit Service 97d2fb
      if ((((uintptr_t) d) & (sizeof (unsigned long) - 1)) == 0)
Packit Service 97d2fb
	*result = *(unsigned long *) d;
Packit Service 97d2fb
      else
Packit Service 97d2fb
	memcpy (result, d, sizeof (unsigned long));
Packit Service 97d2fb
      return true;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  struct iovec local, remote;
Packit Service 97d2fb
  mem_cache->addr = addr & ~((Dwarf_Addr)__LIBDWFL_REMOTE_MEM_CACHE_SIZE - 1);
Packit Service 97d2fb
  local.iov_base = mem_cache->buf;
Packit Service 97d2fb
  local.iov_len = __LIBDWFL_REMOTE_MEM_CACHE_SIZE;
Packit Service 97d2fb
  remote.iov_base = (void *) (uintptr_t) mem_cache->addr;
Packit Service 97d2fb
  remote.iov_len = __LIBDWFL_REMOTE_MEM_CACHE_SIZE;
Packit Service 97d2fb
Packit Service 97d2fb
  ssize_t res = process_vm_readv (pid_arg->tid_attached,
Packit Service 97d2fb
				  &local, 1, &remote, 1, 0);
Packit Service 97d2fb
  if (res != __LIBDWFL_REMOTE_MEM_CACHE_SIZE)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      mem_cache->len = 0;
Packit Service 97d2fb
      return false;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  mem_cache->len = res;
Packit Service 97d2fb
  d = &mem_cache->buf[addr - mem_cache->addr];
Packit Service 97d2fb
  if ((((uintptr_t) d) & (sizeof (unsigned long) - 1)) == 0)
Packit Service 97d2fb
    *result = *(unsigned long *) d;
Packit Service 97d2fb
  else
Packit Service 97d2fb
    memcpy (result, d, sizeof (unsigned long));
Packit Service 97d2fb
  return true;
Packit Service 97d2fb
}
Packit Service 97d2fb
#endif /* HAVE_PROCESS_VM_READV */
Packit Service 97d2fb
Packit Service 97d2fb
static void
Packit Service 97d2fb
clear_cached_memory (struct __libdwfl_pid_arg *pid_arg)
Packit Service 97d2fb
{
Packit Service 97d2fb
  struct __libdwfl_remote_mem_cache *mem_cache = pid_arg->mem_cache;
Packit Service 97d2fb
  if (mem_cache != NULL)
Packit Service 97d2fb
    mem_cache->len = 0;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Note that the result word size depends on the architecture word size.
Packit Service 97d2fb
   That is sizeof long. */
Packit Service 97d2fb
static bool
Packit Service 97d2fb
pid_memory_read (Dwfl *dwfl, Dwarf_Addr addr, Dwarf_Word *result, void *arg)
Packit Service 97d2fb
{
Packit Service 97d2fb
  struct __libdwfl_pid_arg *pid_arg = arg;
Packit Service 97d2fb
  pid_t tid = pid_arg->tid_attached;
Packit Service 97d2fb
  assert (tid > 0);
Packit Service 97d2fb
Packit Service 97d2fb
#ifdef HAVE_PROCESS_VM_READV
Packit Service 97d2fb
  if (read_cached_memory (pid_arg, addr, result))
Packit Service 97d2fb
    return true;
Packit Service 97d2fb
#endif
Packit Service 97d2fb
Packit Service 97d2fb
  Dwfl_Process *process = dwfl->process;
Packit Service 97d2fb
  if (ebl_get_elfclass (process->ebl) == ELFCLASS64)
Packit Service 97d2fb
    {
Packit Service 97d2fb
#if SIZEOF_LONG == 8
Packit Service 97d2fb
      errno = 0;
Packit Service 97d2fb
      *result = ptrace (PTRACE_PEEKDATA, tid, (void *) (uintptr_t) addr, NULL);
Packit Service 97d2fb
      return errno == 0;
Packit Service 97d2fb
#else /* SIZEOF_LONG != 8 */
Packit Service 97d2fb
      /* This should not happen.  */
Packit Service 97d2fb
      return false;
Packit Service 97d2fb
#endif /* SIZEOF_LONG != 8 */
Packit Service 97d2fb
    }
Packit Service 97d2fb
#if SIZEOF_LONG == 8
Packit Service 97d2fb
  /* We do not care about reads unaliged to 4 bytes boundary.
Packit Service 97d2fb
     But 0x...ffc read of 8 bytes could overrun a page.  */
Packit Service 97d2fb
  bool lowered = (addr & 4) != 0;
Packit Service 97d2fb
  if (lowered)
Packit Service 97d2fb
    addr -= 4;
Packit Service 97d2fb
#endif /* SIZEOF_LONG == 8 */
Packit Service 97d2fb
  errno = 0;
Packit Service 97d2fb
  *result = ptrace (PTRACE_PEEKDATA, tid, (void *) (uintptr_t) addr, NULL);
Packit Service 97d2fb
  if (errno != 0)
Packit Service 97d2fb
    return false;
Packit Service 97d2fb
#if SIZEOF_LONG == 8
Packit Service 97d2fb
# if BYTE_ORDER == BIG_ENDIAN
Packit Service 97d2fb
  if (! lowered)
Packit Service 97d2fb
    *result >>= 32;
Packit Service 97d2fb
# else
Packit Service 97d2fb
  if (lowered)
Packit Service 97d2fb
    *result >>= 32;
Packit Service 97d2fb
# endif
Packit Service 97d2fb
#endif /* SIZEOF_LONG == 8 */
Packit Service 97d2fb
  *result &= 0xffffffff;
Packit Service 97d2fb
  return true;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static pid_t
Packit Service 97d2fb
pid_next_thread (Dwfl *dwfl __attribute__ ((unused)), void *dwfl_arg,
Packit Service 97d2fb
		 void **thread_argp)
Packit Service 97d2fb
{
Packit Service 97d2fb
  struct __libdwfl_pid_arg *pid_arg = dwfl_arg;
Packit Service 97d2fb
  struct dirent *dirent;
Packit Service 97d2fb
  /* Start fresh on first traversal. */
Packit Service 97d2fb
  if (*thread_argp == NULL)
Packit Service 97d2fb
    rewinddir (pid_arg->dir);
Packit Service 97d2fb
  do
Packit Service 97d2fb
    {
Packit Service 97d2fb
      errno = 0;
Packit Service 97d2fb
      dirent = readdir (pid_arg->dir);
Packit Service 97d2fb
      if (dirent == NULL)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  if (errno != 0)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      __libdwfl_seterrno (DWFL_E_ERRNO);
Packit Service 97d2fb
	      return -1;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	  return 0;
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
  while (strcmp (dirent->d_name, ".") == 0
Packit Service 97d2fb
	 || strcmp (dirent->d_name, "..") == 0);
Packit Service 97d2fb
  char *end;
Packit Service 97d2fb
  errno = 0;
Packit Service 97d2fb
  long tidl = strtol (dirent->d_name, &end, 10);
Packit Service 97d2fb
  if (errno != 0)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      __libdwfl_seterrno (DWFL_E_ERRNO);
Packit Service 97d2fb
      return -1;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  pid_t tid = tidl;
Packit Service 97d2fb
  if (tidl <= 0 || (end && *end) || tid != tidl)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      __libdwfl_seterrno (DWFL_E_PARSE_PROC);
Packit Service 97d2fb
      return -1;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  *thread_argp = dwfl_arg;
Packit Service 97d2fb
  return tid;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Just checks that the thread id exists.  */
Packit Service 97d2fb
static bool
Packit Service 97d2fb
pid_getthread (Dwfl *dwfl __attribute__ ((unused)), pid_t tid,
Packit Service 97d2fb
	       void *dwfl_arg, void **thread_argp)
Packit Service 97d2fb
{
Packit Service 97d2fb
  *thread_argp = dwfl_arg;
Packit Service 97d2fb
  if (kill (tid, 0) < 0)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      __libdwfl_seterrno (DWFL_E_ERRNO);
Packit Service 97d2fb
      return false;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  return true;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Implement the ebl_set_initial_registers_tid setfunc callback.  */
Packit Service 97d2fb
Packit Service 97d2fb
static bool
Packit Service 97d2fb
pid_thread_state_registers_cb (int firstreg, unsigned nregs,
Packit Service 97d2fb
			       const Dwarf_Word *regs, void *arg)
Packit Service 97d2fb
{
Packit Service 97d2fb
  Dwfl_Thread *thread = (Dwfl_Thread *) arg;
Packit Service 97d2fb
  if (firstreg < 0)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      assert (firstreg == -1);
Packit Service 97d2fb
      assert (nregs == 1);
Packit Service 97d2fb
      INTUSE(dwfl_thread_state_register_pc) (thread, *regs);
Packit Service 97d2fb
      return true;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  assert (nregs > 0);
Packit Service 97d2fb
  return INTUSE(dwfl_thread_state_registers) (thread, firstreg, nregs, regs);
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static bool
Packit Service 97d2fb
pid_set_initial_registers (Dwfl_Thread *thread, void *thread_arg)
Packit Service 97d2fb
{
Packit Service 97d2fb
  struct __libdwfl_pid_arg *pid_arg = thread_arg;
Packit Service 97d2fb
  assert (pid_arg->tid_attached == 0);
Packit Service 97d2fb
  pid_t tid = INTUSE(dwfl_thread_tid) (thread);
Packit Service 97d2fb
  if (! pid_arg->assume_ptrace_stopped
Packit Service 97d2fb
      && ! __libdwfl_ptrace_attach (tid, &pid_arg->tid_was_stopped))
Packit Service 97d2fb
    return false;
Packit Service 97d2fb
  pid_arg->tid_attached = tid;
Packit Service 97d2fb
  Dwfl_Process *process = thread->process;
Packit Service 97d2fb
  Ebl *ebl = process->ebl;
Packit Service 97d2fb
  return ebl_set_initial_registers_tid (ebl, tid,
Packit Service 97d2fb
					pid_thread_state_registers_cb, thread);
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static void
Packit Service 97d2fb
pid_detach (Dwfl *dwfl __attribute__ ((unused)), void *dwfl_arg)
Packit Service 97d2fb
{
Packit Service 97d2fb
  struct __libdwfl_pid_arg *pid_arg = dwfl_arg;
Packit Service 97d2fb
  elf_end (pid_arg->elf);
Packit Service 97d2fb
  free (pid_arg->mem_cache);
Packit Service 97d2fb
  close (pid_arg->elf_fd);
Packit Service 97d2fb
  closedir (pid_arg->dir);
Packit Service 97d2fb
  free (pid_arg);
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
void
Packit Service 97d2fb
internal_function
Packit Service 97d2fb
__libdwfl_ptrace_detach (pid_t tid, bool tid_was_stopped)
Packit Service 97d2fb
{
Packit Service 97d2fb
  /* This handling is needed only on older Linux kernels such as
Packit Service 97d2fb
     2.6.32-358.23.2.el6.ppc64.  Later kernels such as
Packit Service 97d2fb
     3.11.7-200.fc19.x86_64 remember the T (stopped) state
Packit Service 97d2fb
     themselves and no longer need to pass SIGSTOP during
Packit Service 97d2fb
     PTRACE_DETACH.  */
Packit Service 97d2fb
  ptrace (PTRACE_DETACH, tid, NULL,
Packit Service 97d2fb
	  (void *) (intptr_t) (tid_was_stopped ? SIGSTOP : 0));
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static void
Packit Service 97d2fb
pid_thread_detach (Dwfl_Thread *thread, void *thread_arg)
Packit Service 97d2fb
{
Packit Service 97d2fb
  struct __libdwfl_pid_arg *pid_arg = thread_arg;
Packit Service 97d2fb
  pid_t tid = INTUSE(dwfl_thread_tid) (thread);
Packit Service 97d2fb
  assert (pid_arg->tid_attached == tid);
Packit Service 97d2fb
  pid_arg->tid_attached = 0;
Packit Service 97d2fb
  clear_cached_memory (pid_arg);
Packit Service 97d2fb
  if (! pid_arg->assume_ptrace_stopped)
Packit Service 97d2fb
    __libdwfl_ptrace_detach (tid, pid_arg->tid_was_stopped);
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static const Dwfl_Thread_Callbacks pid_thread_callbacks =
Packit Service 97d2fb
{
Packit Service 97d2fb
  pid_next_thread,
Packit Service 97d2fb
  pid_getthread,
Packit Service 97d2fb
  pid_memory_read,
Packit Service 97d2fb
  pid_set_initial_registers,
Packit Service 97d2fb
  pid_detach,
Packit Service 97d2fb
  pid_thread_detach,
Packit Service 97d2fb
};
Packit Service 97d2fb
Packit Service 97d2fb
int
Packit Service 97d2fb
dwfl_linux_proc_attach (Dwfl *dwfl, pid_t pid, bool assume_ptrace_stopped)
Packit Service 97d2fb
{
Packit Service 97d2fb
  char buffer[36];
Packit Service 97d2fb
  FILE *procfile;
Packit Service 97d2fb
  int err = 0; /* The errno to return and set for dwfl->attcherr.  */
Packit Service 97d2fb
Packit Service 97d2fb
  /* Make sure to report the actual PID (thread group leader) to
Packit Service 97d2fb
     dwfl_attach_state.  */
Packit Service 97d2fb
  snprintf (buffer, sizeof (buffer), "/proc/%ld/status", (long) pid);
Packit Service 97d2fb
  procfile = fopen (buffer, "r");
Packit Service 97d2fb
  if (procfile == NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      err = errno;
Packit Service 97d2fb
    fail:
Packit Service 97d2fb
      if (dwfl->process == NULL && dwfl->attacherr == DWFL_E_NOERROR)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  errno = err;
Packit Service 97d2fb
	  dwfl->attacherr = __libdwfl_canon_error (DWFL_E_ERRNO);
Packit Service 97d2fb
	}
Packit Service 97d2fb
      return err;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  char *line = NULL;
Packit Service 97d2fb
  size_t linelen = 0;
Packit Service 97d2fb
  while (getline (&line, &linelen, procfile) >= 0)
Packit Service 97d2fb
    if (strncmp (line, "Tgid:", 5) == 0)
Packit Service 97d2fb
      {
Packit Service 97d2fb
	errno = 0;
Packit Service 97d2fb
	char *endptr;
Packit Service 97d2fb
	long val = strtol (&line[5], &endptr, 10);
Packit Service 97d2fb
	if ((errno == ERANGE && val == LONG_MAX)
Packit Service 97d2fb
	    || *endptr != '\n' || val < 0 || val != (pid_t) val)
Packit Service 97d2fb
	  pid = 0;
Packit Service 97d2fb
	else
Packit Service 97d2fb
	  pid = (pid_t) val;
Packit Service 97d2fb
	break;
Packit Service 97d2fb
      }
Packit Service 97d2fb
  free (line);
Packit Service 97d2fb
  fclose (procfile);
Packit Service 97d2fb
Packit Service 97d2fb
  if (pid == 0)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      err = ESRCH;
Packit Service 97d2fb
      goto fail;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  char name[64];
Packit Service 97d2fb
  int i = snprintf (name, sizeof (name), "/proc/%ld/task", (long) pid);
Packit Service 97d2fb
  if (i <= 0 || i >= (ssize_t) sizeof (name) - 1)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      errno = -ENOMEM;
Packit Service 97d2fb
      goto fail;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  DIR *dir = opendir (name);
Packit Service 97d2fb
  if (dir == NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      err = errno;
Packit Service 97d2fb
      goto fail;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  Elf *elf;
Packit Service 97d2fb
  i = snprintf (name, sizeof (name), "/proc/%ld/exe", (long) pid);
Packit Service 97d2fb
  assert (i > 0 && i < (ssize_t) sizeof (name) - 1);
Packit Service 97d2fb
  int elf_fd = open (name, O_RDONLY);
Packit Service 97d2fb
  if (elf_fd >= 0)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      elf = elf_begin (elf_fd, ELF_C_READ_MMAP, NULL);
Packit Service 97d2fb
      if (elf == NULL)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* Just ignore, dwfl_attach_state will fall back to trying
Packit Service 97d2fb
	     to associate the Dwfl with one of the existing DWfl_Module
Packit Service 97d2fb
	     ELF images (to know the machine/class backend to use).  */
Packit Service 97d2fb
	  close (elf_fd);
Packit Service 97d2fb
	  elf_fd = -1;
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
  else
Packit Service 97d2fb
    elf = NULL;
Packit Service 97d2fb
  struct __libdwfl_pid_arg *pid_arg = malloc (sizeof *pid_arg);
Packit Service 97d2fb
  if (pid_arg == NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      elf_end (elf);
Packit Service 97d2fb
      close (elf_fd);
Packit Service 97d2fb
      closedir (dir);
Packit Service 97d2fb
      err = ENOMEM;
Packit Service 97d2fb
      goto fail;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  pid_arg->dir = dir;
Packit Service 97d2fb
  pid_arg->elf = elf;
Packit Service 97d2fb
  pid_arg->elf_fd = elf_fd;
Packit Service 97d2fb
  pid_arg->mem_cache = NULL;
Packit Service 97d2fb
  pid_arg->tid_attached = 0;
Packit Service 97d2fb
  pid_arg->assume_ptrace_stopped = assume_ptrace_stopped;
Packit Service 97d2fb
  if (! INTUSE(dwfl_attach_state) (dwfl, elf, pid, &pid_thread_callbacks,
Packit Service 97d2fb
				   pid_arg))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      elf_end (elf);
Packit Service 97d2fb
      close (elf_fd);
Packit Service 97d2fb
      closedir (dir);
Packit Service 97d2fb
      free (pid_arg);
Packit Service 97d2fb
      return -1;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  return 0;
Packit Service 97d2fb
}
Packit Service 97d2fb
INTDEF (dwfl_linux_proc_attach)
Packit Service 97d2fb
Packit Service 97d2fb
struct __libdwfl_pid_arg *
Packit Service 97d2fb
internal_function
Packit Service 97d2fb
__libdwfl_get_pid_arg (Dwfl *dwfl)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (dwfl != NULL && dwfl->process != NULL
Packit Service 97d2fb
      && dwfl->process->callbacks == &pid_thread_callbacks)
Packit Service 97d2fb
    return (struct __libdwfl_pid_arg *) dwfl->process->callbacks_arg;
Packit Service 97d2fb
Packit Service 97d2fb
  return NULL;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
#else	/* __linux__ */
Packit Service 97d2fb
Packit Service 97d2fb
bool
Packit Service 97d2fb
internal_function
Packit Service 97d2fb
__libdwfl_ptrace_attach (pid_t tid __attribute__ ((unused)),
Packit Service 97d2fb
			 bool *tid_was_stoppedp __attribute__ ((unused)))
Packit Service 97d2fb
{
Packit Service 97d2fb
  errno = ENOSYS;
Packit Service 97d2fb
  __libdwfl_seterrno (DWFL_E_ERRNO);
Packit Service 97d2fb
  return false;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
void
Packit Service 97d2fb
internal_function
Packit Service 97d2fb
__libdwfl_ptrace_detach (pid_t tid __attribute__ ((unused)),
Packit Service 97d2fb
			 bool tid_was_stopped __attribute__ ((unused)))
Packit Service 97d2fb
{
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
int
Packit Service 97d2fb
dwfl_linux_proc_attach (Dwfl *dwfl __attribute__ ((unused)),
Packit Service 97d2fb
			pid_t pid __attribute__ ((unused)),
Packit Service 97d2fb
			bool assume_ptrace_stopped __attribute__ ((unused)))
Packit Service 97d2fb
{
Packit Service 97d2fb
  return ENOSYS;
Packit Service 97d2fb
}
Packit Service 97d2fb
INTDEF (dwfl_linux_proc_attach)
Packit Service 97d2fb
Packit Service 97d2fb
struct __libdwfl_pid_arg *
Packit Service 97d2fb
internal_function
Packit Service 97d2fb
__libdwfl_get_pid_arg (Dwfl *dwfl __attribute__ ((unused)))
Packit Service 97d2fb
{
Packit Service 97d2fb
  return NULL;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
#endif /* ! __linux __ */
Packit Service 97d2fb