Blame libdwfl/linux-proc-maps.c

Packit Service 97d2fb
/* Standard libdwfl callbacks for debugging a live Linux process.
Packit Service 97d2fb
   Copyright (C) 2005-2010, 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 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 "libdwflP.h"
Packit Service 97d2fb
#include <inttypes.h>
Packit Service 97d2fb
#include <sys/types.h>
Packit Service 97d2fb
#include <sys/stat.h>
Packit Service 97d2fb
#include <errno.h>
Packit Service 97d2fb
#include <stdio.h>
Packit Service 97d2fb
#include <stdio_ext.h>
Packit Service 97d2fb
#include <stdbool.h>
Packit Service 97d2fb
#include <string.h>
Packit Service 97d2fb
#include <stdlib.h>
Packit Service 97d2fb
#include <fcntl.h>
Packit Service 97d2fb
#include <unistd.h>
Packit Service 97d2fb
#include <assert.h>
Packit Service 97d2fb
#include <endian.h>
Packit Service 97d2fb
#include "system.h"
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
#define PROCMAPSFMT	"/proc/%d/maps"
Packit Service 97d2fb
#define PROCMEMFMT	"/proc/%d/mem"
Packit Service 97d2fb
#define PROCAUXVFMT	"/proc/%d/auxv"
Packit Service 97d2fb
#define PROCEXEFMT	"/proc/%d/exe"
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
/* Return ELFCLASS64 or ELFCLASS32 for the main ELF executable.  Return
Packit Service 97d2fb
   ELFCLASSNONE for an error.  */
Packit Service 97d2fb
Packit Service 97d2fb
static unsigned char
Packit Service 97d2fb
get_pid_class (pid_t pid)
Packit Service 97d2fb
{
Packit Service 97d2fb
  char *fname;
Packit Service 97d2fb
  if (asprintf (&fname, PROCEXEFMT, pid) < 0)
Packit Service 97d2fb
    return ELFCLASSNONE;
Packit Service 97d2fb
Packit Service 97d2fb
  int fd = open (fname, O_RDONLY);
Packit Service 97d2fb
  free (fname);
Packit Service 97d2fb
  if (fd < 0)
Packit Service 97d2fb
    return ELFCLASSNONE;
Packit Service 97d2fb
Packit Service 97d2fb
  unsigned char buf[EI_CLASS + 1];
Packit Service 97d2fb
  ssize_t nread = pread_retry (fd, &buf, sizeof buf, 0);
Packit Service 97d2fb
  close (fd);
Packit Service 97d2fb
  if (nread != sizeof buf || buf[EI_MAG0] != ELFMAG0
Packit Service 97d2fb
      || buf[EI_MAG1] != ELFMAG1 || buf[EI_MAG2] != ELFMAG2
Packit Service 97d2fb
      || buf[EI_MAG3] != ELFMAG3
Packit Service 97d2fb
      || (buf[EI_CLASS] != ELFCLASS64 && buf[EI_CLASS] != ELFCLASS32))
Packit Service 97d2fb
    return ELFCLASSNONE;
Packit Service 97d2fb
Packit Service 97d2fb
  return buf[EI_CLASS];
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Search /proc/PID/auxv for the AT_SYSINFO_EHDR tag.
Packit Service 97d2fb
Packit Service 97d2fb
   It would be easiest to call get_pid_class and parse everything according to
Packit Service 97d2fb
   the 32-bit or 64-bit class.  But this would bring the overhead of syscalls
Packit Service 97d2fb
   to open and read the "/proc/%d/exe" file.
Packit Service 97d2fb
Packit Service 97d2fb
   Therefore this function tries to parse the "/proc/%d/auxv" content both
Packit Service 97d2fb
   ways, as if it were the 32-bit format and also if it were the 64-bit format.
Packit Service 97d2fb
   Only if it gives some valid data in both cases get_pid_class gets called.
Packit Service 97d2fb
   In most cases only one of the format bit sizes gives valid data and the
Packit Service 97d2fb
   get_pid_class call overhead can be saved.  */
Packit Service 97d2fb
Packit Service 97d2fb
static int
Packit Service 97d2fb
grovel_auxv (pid_t pid, Dwfl *dwfl, GElf_Addr *sysinfo_ehdr)
Packit Service 97d2fb
{
Packit Service 97d2fb
  char *fname;
Packit Service 97d2fb
  if (asprintf (&fname, PROCAUXVFMT, pid) < 0)
Packit Service 97d2fb
    return ENOMEM;
Packit Service 97d2fb
Packit Service 97d2fb
  int fd = open (fname, O_RDONLY);
Packit Service 97d2fb
  free (fname);
Packit Service 97d2fb
  if (fd < 0)
Packit Service 97d2fb
    return errno == ENOENT ? 0 : errno;
Packit Service 97d2fb
Packit Service 97d2fb
  GElf_Addr sysinfo_ehdr64 = 0;
Packit Service 97d2fb
  GElf_Addr sysinfo_ehdr32 = 0;
Packit Service 97d2fb
  GElf_Addr segment_align64 = dwfl->segment_align;
Packit Service 97d2fb
  GElf_Addr segment_align32 = dwfl->segment_align;
Packit Service 97d2fb
  off_t offset = 0;
Packit Service 97d2fb
  ssize_t nread;
Packit Service 97d2fb
  union
Packit Service 97d2fb
  {
Packit Service 97d2fb
    Elf64_auxv_t a64[64];
Packit Service 97d2fb
    Elf32_auxv_t a32[128];
Packit Service 97d2fb
  } d;
Packit Service 97d2fb
  do
Packit Service 97d2fb
    {
Packit Service 97d2fb
      eu_static_assert (sizeof d.a64 == sizeof d.a32);
Packit Service 97d2fb
      nread = pread_retry (fd, d.a64, sizeof d.a64, offset);
Packit Service 97d2fb
      if (nread < 0)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  int ret = errno;
Packit Service 97d2fb
	  close (fd);
Packit Service 97d2fb
	  return ret;
Packit Service 97d2fb
	}
Packit Service 97d2fb
      for (size_t a32i = 0; a32i < nread / sizeof d.a32[0]; a32i++)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  const Elf32_auxv_t *a32 = d.a32 + a32i;
Packit Service 97d2fb
	  switch (a32->a_type)
Packit Service 97d2fb
	  {
Packit Service 97d2fb
	    case AT_SYSINFO_EHDR:
Packit Service 97d2fb
	      sysinfo_ehdr32 = a32->a_un.a_val;
Packit Service 97d2fb
	      break;
Packit Service 97d2fb
	    case AT_PAGESZ:
Packit Service 97d2fb
	      segment_align32 = a32->a_un.a_val;
Packit Service 97d2fb
	      break;
Packit Service 97d2fb
	  }
Packit Service 97d2fb
	}
Packit Service 97d2fb
      for (size_t a64i = 0; a64i < nread / sizeof d.a64[0]; a64i++)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  const Elf64_auxv_t *a64 = d.a64 + a64i;
Packit Service 97d2fb
	  switch (a64->a_type)
Packit Service 97d2fb
	  {
Packit Service 97d2fb
	    case AT_SYSINFO_EHDR:
Packit Service 97d2fb
	      sysinfo_ehdr64 = a64->a_un.a_val;
Packit Service 97d2fb
	      break;
Packit Service 97d2fb
	    case AT_PAGESZ:
Packit Service 97d2fb
	      segment_align64 = a64->a_un.a_val;
Packit Service 97d2fb
	      break;
Packit Service 97d2fb
	  }
Packit Service 97d2fb
	}
Packit Service 97d2fb
      offset += nread;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  while (nread == sizeof d.a64);
Packit Service 97d2fb
Packit Service 97d2fb
  close (fd);
Packit Service 97d2fb
Packit Service 97d2fb
  bool valid64 = sysinfo_ehdr64 != 0 || segment_align64 != dwfl->segment_align;
Packit Service 97d2fb
  bool valid32 = sysinfo_ehdr32 != 0 || segment_align32 != dwfl->segment_align;
Packit Service 97d2fb
Packit Service 97d2fb
  unsigned char pid_class = ELFCLASSNONE;
Packit Service 97d2fb
  if (valid64 && valid32)
Packit Service 97d2fb
    pid_class = get_pid_class (pid);
Packit Service 97d2fb
Packit Service 97d2fb
  if (pid_class == ELFCLASS64 || (valid64 && ! valid32))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      *sysinfo_ehdr = sysinfo_ehdr64;
Packit Service 97d2fb
      dwfl->segment_align = segment_align64;
Packit Service 97d2fb
      return 0;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  if (pid_class == ELFCLASS32 || (! valid64 && valid32))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      *sysinfo_ehdr = sysinfo_ehdr32;
Packit Service 97d2fb
      dwfl->segment_align = segment_align32;
Packit Service 97d2fb
      return 0;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  return ENOEXEC;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static inline bool
Packit Service 97d2fb
do_report (Dwfl *dwfl, char **plast_file, Dwarf_Addr low, Dwarf_Addr high)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (*plast_file != NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      Dwfl_Module *mod = INTUSE(dwfl_report_module) (dwfl, *plast_file,
Packit Service 97d2fb
						     low, high);
Packit Service 97d2fb
      free (*plast_file);
Packit Service 97d2fb
      *plast_file = NULL;
Packit Service 97d2fb
      if (unlikely (mod == NULL))
Packit Service 97d2fb
        return true;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  return false;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
#define report() do_report(dwfl, &last_file, low, high)
Packit Service 97d2fb
Packit Service 97d2fb
static int
Packit Service 97d2fb
proc_maps_report (Dwfl *dwfl, FILE *f, GElf_Addr sysinfo_ehdr, pid_t pid)
Packit Service 97d2fb
{
Packit Service 97d2fb
  unsigned int last_dmajor = -1, last_dminor = -1;
Packit Service 97d2fb
  uint64_t last_ino = -1;
Packit Service 97d2fb
  char *last_file = NULL;
Packit Service 97d2fb
  Dwarf_Addr low = 0, high = 0;
Packit Service 97d2fb
Packit Service 97d2fb
  char *line = NULL;
Packit Service 97d2fb
  size_t linesz;
Packit Service 97d2fb
  ssize_t len;
Packit Service 97d2fb
  while ((len = getline (&line, &linesz, f)) > 0)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (line[len - 1] == '\n')
Packit Service 97d2fb
	line[len - 1] = '\0';
Packit Service 97d2fb
Packit Service 97d2fb
      Dwarf_Addr start, end, offset;
Packit Service 97d2fb
      unsigned int dmajor, dminor;
Packit Service 97d2fb
      uint64_t ino;
Packit Service 97d2fb
      int nread = -1;
Packit Service 97d2fb
      if (sscanf (line, "%" PRIx64 "-%" PRIx64 " %*s %" PRIx64
Packit Service 97d2fb
		  " %x:%x %" PRIu64 " %n",
Packit Service 97d2fb
		  &start, &end, &offset, &dmajor, &dminor, &ino, &nread) < 6
Packit Service 97d2fb
	  || nread <= 0)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  free (line);
Packit Service 97d2fb
	  free (last_file);
Packit Service 97d2fb
	  return ENOEXEC;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      /* If this is the special mapping AT_SYSINFO_EHDR pointed us at,
Packit Service 97d2fb
	 report the last one and then this special one.  */
Packit Service 97d2fb
      if (start == sysinfo_ehdr && start != 0)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  if (report ())
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	    bad_report:
Packit Service 97d2fb
	      free (line);
Packit Service 97d2fb
	      return -1;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
Packit Service 97d2fb
	  low = start;
Packit Service 97d2fb
	  high = end;
Packit Service 97d2fb
	  if (asprintf (&last_file, "[vdso: %d]", (int) pid) < 0
Packit Service 97d2fb
	      || report ())
Packit Service 97d2fb
	    goto bad_report;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      char *file = line + nread + strspn (line + nread, " \t");
Packit Service 97d2fb
      if (file[0] != '/' || (ino == 0 && dmajor == 0 && dminor == 0))
Packit Service 97d2fb
	/* This line doesn't indicate a file mapping.  */
Packit Service 97d2fb
	continue;
Packit Service 97d2fb
Packit Service 97d2fb
      if (last_file != NULL
Packit Service 97d2fb
	  && ino == last_ino && dmajor == last_dmajor && dminor == last_dminor)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* This is another portion of the same file's mapping.  */
Packit Service 97d2fb
	  if (strcmp (last_file, file) != 0)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      free (last_file);
Packit Service 97d2fb
	      goto bad_report;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	  high = end;
Packit Service 97d2fb
	}
Packit Service 97d2fb
      else
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* This is a different file mapping.  Report the last one.  */
Packit Service 97d2fb
	  if (report ())
Packit Service 97d2fb
	    goto bad_report;
Packit Service 97d2fb
	  low = start;
Packit Service 97d2fb
	  high = end;
Packit Service 97d2fb
	  last_file = strdup (file);
Packit Service 97d2fb
	  last_ino = ino;
Packit Service 97d2fb
	  last_dmajor = dmajor;
Packit Service 97d2fb
	  last_dminor = dminor;
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
  free (line);
Packit Service 97d2fb
Packit Service 97d2fb
  int result = ferror_unlocked (f) ? errno : feof_unlocked (f) ? 0 : ENOEXEC;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Report the final one.  */
Packit Service 97d2fb
  bool lose = report ();
Packit Service 97d2fb
Packit Service 97d2fb
  return result != 0 ? result : lose ? -1 : 0;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
int
Packit Service 97d2fb
dwfl_linux_proc_maps_report (Dwfl *dwfl, FILE *f)
Packit Service 97d2fb
{
Packit Service 97d2fb
  return proc_maps_report (dwfl, f, 0, 0);
Packit Service 97d2fb
}
Packit Service 97d2fb
INTDEF (dwfl_linux_proc_maps_report)
Packit Service 97d2fb
Packit Service 97d2fb
int
Packit Service 97d2fb
dwfl_linux_proc_report (Dwfl *dwfl, pid_t pid)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (dwfl == NULL)
Packit Service 97d2fb
    return -1;
Packit Service 97d2fb
Packit Service 97d2fb
  /* We'll notice the AT_SYSINFO_EHDR address specially when we hit it.  */
Packit Service 97d2fb
  GElf_Addr sysinfo_ehdr = 0;
Packit Service 97d2fb
  int result = grovel_auxv (pid, dwfl, &sysinfo_ehdr);
Packit Service 97d2fb
  if (result != 0)
Packit Service 97d2fb
    return result;
Packit Service 97d2fb
Packit Service 97d2fb
  char *fname;
Packit Service 97d2fb
  if (asprintf (&fname, PROCMAPSFMT, pid) < 0)
Packit Service 97d2fb
    return ENOMEM;
Packit Service 97d2fb
Packit Service 97d2fb
  FILE *f = fopen (fname, "r");
Packit Service 97d2fb
  free (fname);
Packit Service 97d2fb
  if (f == NULL)
Packit Service 97d2fb
    return errno;
Packit Service 97d2fb
Packit Service 97d2fb
  (void) __fsetlocking (f, FSETLOCKING_BYCALLER);
Packit Service 97d2fb
Packit Service 97d2fb
  result = proc_maps_report (dwfl, f, sysinfo_ehdr, pid);
Packit Service 97d2fb
Packit Service 97d2fb
  fclose (f);
Packit Service 97d2fb
Packit Service 97d2fb
  return result;
Packit Service 97d2fb
}
Packit Service 97d2fb
INTDEF (dwfl_linux_proc_report)
Packit Service 97d2fb
Packit Service 97d2fb
static ssize_t
Packit Service 97d2fb
read_proc_memory (void *arg, void *data, GElf_Addr address,
Packit Service 97d2fb
		  size_t minread, size_t maxread)
Packit Service 97d2fb
{
Packit Service 97d2fb
  const int fd = *(const int *) arg;
Packit Service 97d2fb
Packit Service 97d2fb
  /* This code relies on the fact the Linux kernel accepts negative
Packit Service 97d2fb
     offsets when seeking /dev/$$/mem files, as a special case. In
Packit Service 97d2fb
     particular pread cannot be used here, because it will always
Packit Service 97d2fb
     return EINVAL when passed a negative offset.  */
Packit Service 97d2fb
Packit Service 97d2fb
  if (lseek (fd, (off_t) address, SEEK_SET) == -1)
Packit Service 97d2fb
    return -1;
Packit Service 97d2fb
Packit Service 97d2fb
  ssize_t nread = read (fd, data, maxread);
Packit Service 97d2fb
Packit Service 97d2fb
  if (nread > 0 && (size_t) nread < minread)
Packit Service 97d2fb
    nread = 0;
Packit Service 97d2fb
  return nread;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
extern Elf *elf_from_remote_memory (GElf_Addr ehdr_vma,
Packit Service 97d2fb
				    GElf_Xword pagesize,
Packit Service 97d2fb
				    GElf_Addr *loadbasep,
Packit Service 97d2fb
				    ssize_t (*read_memory) (void *arg,
Packit Service 97d2fb
							    void *data,
Packit Service 97d2fb
							    GElf_Addr address,
Packit Service 97d2fb
							    size_t minread,
Packit Service 97d2fb
							    size_t maxread),
Packit Service 97d2fb
				    void *arg);
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
/* Dwfl_Callbacks.find_elf */
Packit Service 97d2fb
Packit Service 97d2fb
int
Packit Service 97d2fb
dwfl_linux_proc_find_elf (Dwfl_Module *mod __attribute__ ((unused)),
Packit Service 97d2fb
			  void **userdata __attribute__ ((unused)),
Packit Service 97d2fb
			  const char *module_name, Dwarf_Addr base,
Packit Service 97d2fb
			  char **file_name, Elf **elfp)
Packit Service 97d2fb
{
Packit Service 97d2fb
  int pid = -1;
Packit Service 97d2fb
  if (module_name[0] == '/')
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* When this callback is used together with dwfl_linux_proc_report
Packit Service 97d2fb
	 then we might see mappings of special character devices.  Make
Packit Service 97d2fb
	 sure we only open and return regular files.  Special devices
Packit Service 97d2fb
	 might hang on open or read.  (deleted) files are super special.
Packit Service 97d2fb
	 The image might come from memory if we are attached.  */
Packit Service 97d2fb
      struct stat sb;
Packit Service 97d2fb
      if (stat (module_name, &sb) == -1 || (sb.st_mode & S_IFMT) != S_IFREG)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  if (strcmp (strrchr (module_name, ' ') ?: "", " (deleted)") == 0)
Packit Service 97d2fb
	    pid = INTUSE(dwfl_pid) (mod->dwfl);
Packit Service 97d2fb
	  else
Packit Service 97d2fb
	    return -1;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      if (pid == -1)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  int fd = open (module_name, O_RDONLY);
Packit Service 97d2fb
	  if (fd >= 0)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      *file_name = strdup (module_name);
Packit Service 97d2fb
	      if (*file_name == NULL)
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  close (fd);
Packit Service 97d2fb
		  return ENOMEM;
Packit Service 97d2fb
		}
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	  return fd;
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  if (pid != -1 || sscanf (module_name, "[vdso: %d]", &pid) == 1)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* Special case for in-memory ELF image.  */
Packit Service 97d2fb
Packit Service 97d2fb
      bool detach = false;
Packit Service 97d2fb
      bool tid_was_stopped = false;
Packit Service 97d2fb
      struct __libdwfl_pid_arg *pid_arg = __libdwfl_get_pid_arg (mod->dwfl);
Packit Service 97d2fb
      if (pid_arg != NULL && ! pid_arg->assume_ptrace_stopped)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* If any thread is already attached we are fine.  Read
Packit Service 97d2fb
	     through that thread.  It doesn't have to be the main
Packit Service 97d2fb
	     thread pid.  */
Packit Service 97d2fb
	  pid_t tid = pid_arg->tid_attached;
Packit Service 97d2fb
	  if (tid != 0)
Packit Service 97d2fb
	    pid = tid;
Packit Service 97d2fb
	  else
Packit Service 97d2fb
	    detach = __libdwfl_ptrace_attach (pid, &tid_was_stopped);
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      char *fname;
Packit Service 97d2fb
      if (asprintf (&fname, PROCMEMFMT, pid) < 0)
Packit Service 97d2fb
	goto detach;
Packit Service 97d2fb
Packit Service 97d2fb
      int fd = open (fname, O_RDONLY);
Packit Service 97d2fb
      free (fname);
Packit Service 97d2fb
      if (fd < 0)
Packit Service 97d2fb
	goto detach;
Packit Service 97d2fb
Packit Service 97d2fb
      *elfp = elf_from_remote_memory (base, sysconf (_SC_PAGESIZE), NULL,
Packit Service 97d2fb
				      &read_proc_memory, &fd;;
Packit Service 97d2fb
Packit Service 97d2fb
      close (fd);
Packit Service 97d2fb
Packit Service 97d2fb
      *file_name = NULL;
Packit Service 97d2fb
Packit Service 97d2fb
    detach:
Packit Service 97d2fb
      if (detach)
Packit Service 97d2fb
	__libdwfl_ptrace_detach (pid, tid_was_stopped);
Packit Service 97d2fb
      return -1;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  return -1;
Packit Service 97d2fb
}
Packit Service 97d2fb
INTDEF (dwfl_linux_proc_find_elf)