125b3c049e70834cf33790a28643ab058b507b35cBen Cheng/* Standard libdwfl callbacks for debugging a live Linux process.
203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   Copyright (C) 2005-2010, 2013, 2014 Red Hat, Inc.
303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   This file is part of elfutils.
425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   This file is free software; you can redistribute it and/or modify
603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   it under the terms of either
725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes     * the GNU Lesser General Public License as published by the Free
903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes       Software Foundation; either version 3 of the License, or (at
1003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes       your option) any later version
1103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
1203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   or
1303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
1403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes     * the GNU General Public License as published by the Free
1503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes       Software Foundation; either version 2 of the License, or (at
1603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes       your option) any later version
1703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
1803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   or both in parallel, as here.
1903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
2003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   elfutils is distributed in the hope that it will be useful, but
2125b3c049e70834cf33790a28643ab058b507b35cBen Cheng   WITHOUT ANY WARRANTY; without even the implied warranty of
2225b3c049e70834cf33790a28643ab058b507b35cBen Cheng   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
2325b3c049e70834cf33790a28643ab058b507b35cBen Cheng   General Public License for more details.
2425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
2503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   You should have received copies of the GNU General Public License and
2603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   the GNU Lesser General Public License along with this program.  If
2703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   not, see <http://www.gnu.org/licenses/>.  */
2825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
2925b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include "libdwflP.h"
3025b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <inttypes.h>
3125b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <sys/types.h>
3203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#include <sys/stat.h>
3325b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <errno.h>
3425b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <stdio.h>
3525b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <stdio_ext.h>
3625b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <stdbool.h>
3725b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <string.h>
3825b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <stdlib.h>
3925b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <fcntl.h>
4025b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <unistd.h>
4125b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <assert.h>
4225b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <endian.h>
4303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#include "system.h"
4425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
4525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
4625b3c049e70834cf33790a28643ab058b507b35cBen Cheng#define PROCMAPSFMT	"/proc/%d/maps"
4725b3c049e70834cf33790a28643ab058b507b35cBen Cheng#define PROCMEMFMT	"/proc/%d/mem"
4825b3c049e70834cf33790a28643ab058b507b35cBen Cheng#define PROCAUXVFMT	"/proc/%d/auxv"
4903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#define PROCEXEFMT	"/proc/%d/exe"
5003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
5103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
5203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes/* Return ELFCLASS64 or ELFCLASS32 for the main ELF executable.  Return
5303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   ELFCLASSNONE for an error.  */
5403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
5503333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstatic unsigned char
5603333823c75a1c1887e923828113a1b0fd12020cElliott Hughesget_pid_class (pid_t pid)
5703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes{
5803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  char *fname;
5903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  if (asprintf (&fname, PROCEXEFMT, pid) < 0)
6003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    return ELFCLASSNONE;
6103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
6203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  int fd = open64 (fname, O_RDONLY);
6303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  free (fname);
6403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  if (fd < 0)
6503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    return ELFCLASSNONE;
6603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
6703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  unsigned char buf[EI_CLASS + 1];
6803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  ssize_t nread = pread_retry (fd, &buf, sizeof buf, 0);
6903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  close (fd);
7003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  if (nread != sizeof buf || buf[EI_MAG0] != ELFMAG0
7103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      || buf[EI_MAG1] != ELFMAG1 || buf[EI_MAG2] != ELFMAG2
7203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      || buf[EI_MAG3] != ELFMAG3
7303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      || (buf[EI_CLASS] != ELFCLASS64 && buf[EI_CLASS] != ELFCLASS32))
7403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    return ELFCLASSNONE;
7525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
7603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  return buf[EI_CLASS];
7703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes}
7803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
7903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes/* Search /proc/PID/auxv for the AT_SYSINFO_EHDR tag.
8003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
8103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   It would be easiest to call get_pid_class and parse everything according to
8203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   the 32-bit or 64-bit class.  But this would bring the overhead of syscalls
8303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   to open and read the "/proc/%d/exe" file.
8425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
8503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   Therefore this function tries to parse the "/proc/%d/auxv" content both
8603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   ways, as if it were the 32-bit format and also if it were the 64-bit format.
8703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   Only if it gives some valid data in both cases get_pid_class gets called.
8803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   In most cases only one of the format bit sizes gives valid data and the
8903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   get_pid_class call overhead can be saved.  */
9025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
9125b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic int
9225b3c049e70834cf33790a28643ab058b507b35cBen Chenggrovel_auxv (pid_t pid, Dwfl *dwfl, GElf_Addr *sysinfo_ehdr)
9325b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
9425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  char *fname;
9525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (asprintf (&fname, PROCAUXVFMT, pid) < 0)
9625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return ENOMEM;
9725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
9825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  int fd = open64 (fname, O_RDONLY);
9925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  free (fname);
10025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (fd < 0)
10125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return errno == ENOENT ? 0 : errno;
10225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
10303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  GElf_Addr sysinfo_ehdr64 = 0;
10403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  GElf_Addr sysinfo_ehdr32 = 0;
10503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  GElf_Addr segment_align64 = dwfl->segment_align;
10603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  GElf_Addr segment_align32 = dwfl->segment_align;
10703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  off_t offset = 0;
10825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  ssize_t nread;
10903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  union
11003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  {
11103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    Elf64_auxv_t a64[64];
11203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    Elf32_auxv_t a32[128];
11303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  } d;
11425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  do
11525b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
11603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      eu_static_assert (sizeof d.a64 == sizeof d.a32);
11703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      nread = pread_retry (fd, d.a64, sizeof d.a64, offset);
11803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      if (nread < 0)
11925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
12003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  int ret = errno;
12103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  close (fd);
12203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  return ret;
12303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	}
12403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      for (size_t a32i = 0; a32i < nread / sizeof d.a32[0]; a32i++)
12503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	{
12603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  const Elf32_auxv_t *a32 = d.a32 + a32i;
12703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  switch (a32->a_type)
12803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  {
12903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    case AT_SYSINFO_EHDR:
13003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      sysinfo_ehdr32 = a32->a_un.a_val;
13125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      break;
13203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    case AT_PAGESZ:
13303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      segment_align32 = a32->a_un.a_val;
13425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      break;
13503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  }
13603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	}
13703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      for (size_t a64i = 0; a64i < nread / sizeof d.a64[0]; a64i++)
13803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	{
13903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  const Elf64_auxv_t *a64 = d.a64 + a64i;
14003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  switch (a64->a_type)
14103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  {
14203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    case AT_SYSINFO_EHDR:
14303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      sysinfo_ehdr64 = a64->a_un.a_val;
14425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      break;
14503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    case AT_PAGESZ:
14603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      segment_align64 = a64->a_un.a_val;
14703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      break;
14803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  }
14925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
15003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      offset += nread;
15125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
15203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  while (nread == sizeof d.a64);
15325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
15425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  close (fd);
15525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
15603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  bool valid64 = sysinfo_ehdr64 != 0 || segment_align64 != dwfl->segment_align;
15703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  bool valid32 = sysinfo_ehdr32 != 0 || segment_align32 != dwfl->segment_align;
15803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
15903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  unsigned char pid_class = ELFCLASSNONE;
16003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  if (valid64 && valid32)
16103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    pid_class = get_pid_class (pid);
16203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
16303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  if (pid_class == ELFCLASS64 || (valid64 && ! valid32))
16403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    {
16503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      *sysinfo_ehdr = sysinfo_ehdr64;
16603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      dwfl->segment_align = segment_align64;
16703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      return 0;
16803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    }
16903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  if (pid_class == ELFCLASS32 || (! valid64 && valid32))
17003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    {
17103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      *sysinfo_ehdr = sysinfo_ehdr32;
17203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      dwfl->segment_align = segment_align32;
17303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      return 0;
17403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    }
17503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  return ENOEXEC;
17625b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
17725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
17825b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic int
17925b3c049e70834cf33790a28643ab058b507b35cBen Chengproc_maps_report (Dwfl *dwfl, FILE *f, GElf_Addr sysinfo_ehdr, pid_t pid)
18025b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
18125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  unsigned int last_dmajor = -1, last_dminor = -1;
18225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  uint64_t last_ino = -1;
18325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  char *last_file = NULL;
18425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Dwarf_Addr low = 0, high = 0;
18525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
18625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  inline bool report (void)
18725b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
18825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (last_file != NULL)
18925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
19025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  Dwfl_Module *mod = INTUSE(dwfl_report_module) (dwfl, last_file,
19125b3c049e70834cf33790a28643ab058b507b35cBen Cheng							 low, high);
19225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  free (last_file);
19325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  last_file = NULL;
19425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (unlikely (mod == NULL))
19525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    return true;
19625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
19725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      return false;
19825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
19925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
20025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  char *line = NULL;
20125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  size_t linesz;
20225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  ssize_t len;
20325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  while ((len = getline (&line, &linesz, f)) > 0)
20425b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
20525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (line[len - 1] == '\n')
20625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	line[len - 1] = '\0';
20725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
20825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      Dwarf_Addr start, end, offset;
20925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      unsigned int dmajor, dminor;
21025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      uint64_t ino;
21125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      int nread = -1;
21225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (sscanf (line, "%" PRIx64 "-%" PRIx64 " %*s %" PRIx64
21325b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  " %x:%x %" PRIi64 " %n",
21425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  &start, &end, &offset, &dmajor, &dminor, &ino, &nread) < 6
21525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  || nread <= 0)
21625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
21725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  free (line);
21825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  return ENOEXEC;
21925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
22025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
22125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      /* If this is the special mapping AT_SYSINFO_EHDR pointed us at,
22225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	 report the last one and then this special one.  */
22325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (start == sysinfo_ehdr && start != 0)
22425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
22525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (report ())
22625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    {
22725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    bad_report:
22825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      free (line);
22925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      return -1;
23025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    }
23125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
23225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  low = start;
23325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  high = end;
23425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (asprintf (&last_file, "[vdso: %d]", (int) pid) < 0
23525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      || report ())
23625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    goto bad_report;
23725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
23825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
23925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      char *file = line + nread + strspn (line + nread, " \t");
24003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      if (file[0] != '/' || (ino == 0 && dmajor == 0 && dminor == 0))
24125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	/* This line doesn't indicate a file mapping.  */
24225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	continue;
24325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
24425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (last_file != NULL
24525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  && ino == last_ino && dmajor == last_dmajor && dminor == last_dminor)
24625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
24725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  /* This is another portion of the same file's mapping.  */
24803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  if (strcmp (last_file, file) != 0)
24903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    goto bad_report;
25025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  high = end;
25125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
25225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      else
25325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
25425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  /* This is a different file mapping.  Report the last one.  */
25525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (report ())
25625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    goto bad_report;
25725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  low = start;
25825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  high = end;
25925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  last_file = strdup (file);
26025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  last_ino = ino;
26125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  last_dmajor = dmajor;
26225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  last_dminor = dminor;
26325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
26425b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
26525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  free (line);
26625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
26725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  int result = ferror_unlocked (f) ? errno : feof_unlocked (f) ? 0 : ENOEXEC;
26825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
26925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Report the final one.  */
27025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  bool lose = report ();
27125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
27225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  return result != 0 ? result : lose ? -1 : 0;
27325b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
27425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
27525b3c049e70834cf33790a28643ab058b507b35cBen Chengint
27625b3c049e70834cf33790a28643ab058b507b35cBen Chengdwfl_linux_proc_maps_report (Dwfl *dwfl, FILE *f)
27725b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
27825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  return proc_maps_report (dwfl, f, 0, 0);
27925b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
28025b3c049e70834cf33790a28643ab058b507b35cBen ChengINTDEF (dwfl_linux_proc_maps_report)
28125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
28225b3c049e70834cf33790a28643ab058b507b35cBen Chengint
28325b3c049e70834cf33790a28643ab058b507b35cBen Chengdwfl_linux_proc_report (Dwfl *dwfl, pid_t pid)
28425b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
28525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (dwfl == NULL)
28625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return -1;
28725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
28825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* We'll notice the AT_SYSINFO_EHDR address specially when we hit it.  */
28925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Addr sysinfo_ehdr = 0;
29025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  int result = grovel_auxv (pid, dwfl, &sysinfo_ehdr);
29125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (result != 0)
29225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return result;
29325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
29425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  char *fname;
29525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (asprintf (&fname, PROCMAPSFMT, pid) < 0)
29625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return ENOMEM;
29725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
29825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  FILE *f = fopen (fname, "r");
29925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  free (fname);
30025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (f == NULL)
30125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return errno;
30225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
30325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  (void) __fsetlocking (f, FSETLOCKING_BYCALLER);
30425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
30525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  result = proc_maps_report (dwfl, f, sysinfo_ehdr, pid);
30625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
30725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  fclose (f);
30825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
30925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  return result;
31025b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
31125b3c049e70834cf33790a28643ab058b507b35cBen ChengINTDEF (dwfl_linux_proc_report)
31225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
31325b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic ssize_t
31425b3c049e70834cf33790a28643ab058b507b35cBen Chengread_proc_memory (void *arg, void *data, GElf_Addr address,
31525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  size_t minread, size_t maxread)
31625b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
31725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  const int fd = *(const int *) arg;
31825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  ssize_t nread = pread64 (fd, data, maxread, (off64_t) address);
31925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Some kernels don't actually let us do this read, ignore those errors.  */
32025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (nread < 0 && (errno == EINVAL || errno == EPERM))
32125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return 0;
32225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (nread > 0 && (size_t) nread < minread)
32325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    nread = 0;
32425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  return nread;
32525b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
32625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
32725b3c049e70834cf33790a28643ab058b507b35cBen Chengextern Elf *elf_from_remote_memory (GElf_Addr ehdr_vma,
32803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes				    GElf_Xword pagesize,
32925b3c049e70834cf33790a28643ab058b507b35cBen Cheng				    GElf_Addr *loadbasep,
33025b3c049e70834cf33790a28643ab058b507b35cBen Cheng				    ssize_t (*read_memory) (void *arg,
33125b3c049e70834cf33790a28643ab058b507b35cBen Cheng							    void *data,
33225b3c049e70834cf33790a28643ab058b507b35cBen Cheng							    GElf_Addr address,
33325b3c049e70834cf33790a28643ab058b507b35cBen Cheng							    size_t minread,
33425b3c049e70834cf33790a28643ab058b507b35cBen Cheng							    size_t maxread),
33525b3c049e70834cf33790a28643ab058b507b35cBen Cheng				    void *arg);
33625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
33725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
33825b3c049e70834cf33790a28643ab058b507b35cBen Cheng/* Dwfl_Callbacks.find_elf */
33925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
34025b3c049e70834cf33790a28643ab058b507b35cBen Chengint
34125b3c049e70834cf33790a28643ab058b507b35cBen Chengdwfl_linux_proc_find_elf (Dwfl_Module *mod __attribute__ ((unused)),
34225b3c049e70834cf33790a28643ab058b507b35cBen Cheng			  void **userdata __attribute__ ((unused)),
34325b3c049e70834cf33790a28643ab058b507b35cBen Cheng			  const char *module_name, Dwarf_Addr base,
34425b3c049e70834cf33790a28643ab058b507b35cBen Cheng			  char **file_name, Elf **elfp)
34525b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
34603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  int pid = -1;
34725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (module_name[0] == '/')
34825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
34903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      /* When this callback is used together with dwfl_linux_proc_report
35003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	 then we might see mappings of special character devices.  Make
35103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	 sure we only open and return regular files.  Special devices
35203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	 might hang on open or read.  (deleted) files are super special.
35303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	 The image might come from memory if we are attached.  */
35403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      struct stat sb;
35503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      if (stat (module_name, &sb) == -1 || (sb.st_mode & S_IFMT) != S_IFREG)
35603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	{
35703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  if (strcmp (strrchr (module_name, ' ') ?: "", " (deleted)") == 0)
35803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    pid = INTUSE(dwfl_pid) (mod->dwfl);
35903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  else
36003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    return -1;
36103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	}
36203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
36303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      if (pid == -1)
36425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
36503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  int fd = open64 (module_name, O_RDONLY);
36603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  if (fd >= 0)
36725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    {
36803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      *file_name = strdup (module_name);
36903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      if (*file_name == NULL)
37003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		{
37103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		  close (fd);
37203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		  return ENOMEM;
37303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		}
37425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    }
37503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  return fd;
37625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
37725b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
37825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
37903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  if (pid != -1 || sscanf (module_name, "[vdso: %d]", &pid) == 1)
38025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
38125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      /* Special case for in-memory ELF image.  */
38225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
38303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      bool detach = false;
38403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      bool tid_was_stopped = false;
38503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      struct __libdwfl_pid_arg *pid_arg = __libdwfl_get_pid_arg (mod->dwfl);
38603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      if (pid_arg != NULL && ! pid_arg->assume_ptrace_stopped)
38703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	{
38803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  /* If any thread is already attached we are fine.  Read
38903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	     through that thread.  It doesn't have to be the main
39003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	     thread pid.  */
39103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  pid_t tid = pid_arg->tid_attached;
39203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  if (tid != 0)
39303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    pid = tid;
39403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  else
39503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    detach = __libdwfl_ptrace_attach (pid, &tid_was_stopped);
39603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	}
39703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
39825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      char *fname;
39925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (asprintf (&fname, PROCMEMFMT, pid) < 0)
40003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	goto detach;
40125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
40225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      int fd = open64 (fname, O_RDONLY);
40325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      free (fname);
40425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (fd < 0)
40503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	goto detach;
40625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
40703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      *elfp = elf_from_remote_memory (base, getpagesize (), NULL,
40803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes				      &read_proc_memory, &fd);
40925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
41025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      close (fd);
41125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
41225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      *file_name = NULL;
41303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
41403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    detach:
41503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      if (detach)
41603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	__libdwfl_ptrace_detach (pid, tid_was_stopped);
41725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      return -1;
41825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
41925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
42025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  return -1;
42125b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
42225b3c049e70834cf33790a28643ab058b507b35cBen ChengINTDEF (dwfl_linux_proc_find_elf)
423