1/* Standard libdwfl callbacks for debugging a live Linux process.
2   Copyright (C) 2005-2010, 2013, 2014 Red Hat, Inc.
3   This file is part of elfutils.
4
5   This file is free software; you can redistribute it and/or modify
6   it under the terms of either
7
8     * the GNU Lesser General Public License as published by the Free
9       Software Foundation; either version 3 of the License, or (at
10       your option) any later version
11
12   or
13
14     * the GNU General Public License as published by the Free
15       Software Foundation; either version 2 of the License, or (at
16       your option) any later version
17
18   or both in parallel, as here.
19
20   elfutils is distributed in the hope that it will be useful, but
21   WITHOUT ANY WARRANTY; without even the implied warranty of
22   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23   General Public License for more details.
24
25   You should have received copies of the GNU General Public License and
26   the GNU Lesser General Public License along with this program.  If
27   not, see <http://www.gnu.org/licenses/>.  */
28
29#include "libdwflP.h"
30#include <inttypes.h>
31#include <sys/types.h>
32#include <sys/stat.h>
33#include <errno.h>
34#include <stdio.h>
35#include <stdio_ext.h>
36#include <stdbool.h>
37#include <string.h>
38#include <stdlib.h>
39#include <fcntl.h>
40#include <unistd.h>
41#include <assert.h>
42#include <endian.h>
43#include "system.h"
44
45
46#define PROCMAPSFMT	"/proc/%d/maps"
47#define PROCMEMFMT	"/proc/%d/mem"
48#define PROCAUXVFMT	"/proc/%d/auxv"
49#define PROCEXEFMT	"/proc/%d/exe"
50
51
52/* Return ELFCLASS64 or ELFCLASS32 for the main ELF executable.  Return
53   ELFCLASSNONE for an error.  */
54
55static unsigned char
56get_pid_class (pid_t pid)
57{
58  char *fname;
59  if (asprintf (&fname, PROCEXEFMT, pid) < 0)
60    return ELFCLASSNONE;
61
62  int fd = open (fname, O_RDONLY);
63  free (fname);
64  if (fd < 0)
65    return ELFCLASSNONE;
66
67  unsigned char buf[EI_CLASS + 1];
68  ssize_t nread = pread_retry (fd, &buf, sizeof buf, 0);
69  close (fd);
70  if (nread != sizeof buf || buf[EI_MAG0] != ELFMAG0
71      || buf[EI_MAG1] != ELFMAG1 || buf[EI_MAG2] != ELFMAG2
72      || buf[EI_MAG3] != ELFMAG3
73      || (buf[EI_CLASS] != ELFCLASS64 && buf[EI_CLASS] != ELFCLASS32))
74    return ELFCLASSNONE;
75
76  return buf[EI_CLASS];
77}
78
79/* Search /proc/PID/auxv for the AT_SYSINFO_EHDR tag.
80
81   It would be easiest to call get_pid_class and parse everything according to
82   the 32-bit or 64-bit class.  But this would bring the overhead of syscalls
83   to open and read the "/proc/%d/exe" file.
84
85   Therefore this function tries to parse the "/proc/%d/auxv" content both
86   ways, as if it were the 32-bit format and also if it were the 64-bit format.
87   Only if it gives some valid data in both cases get_pid_class gets called.
88   In most cases only one of the format bit sizes gives valid data and the
89   get_pid_class call overhead can be saved.  */
90
91static int
92grovel_auxv (pid_t pid, Dwfl *dwfl, GElf_Addr *sysinfo_ehdr)
93{
94  char *fname;
95  if (asprintf (&fname, PROCAUXVFMT, pid) < 0)
96    return ENOMEM;
97
98  int fd = open (fname, O_RDONLY);
99  free (fname);
100  if (fd < 0)
101    return errno == ENOENT ? 0 : errno;
102
103  GElf_Addr sysinfo_ehdr64 = 0;
104  GElf_Addr sysinfo_ehdr32 = 0;
105  GElf_Addr segment_align64 = dwfl->segment_align;
106  GElf_Addr segment_align32 = dwfl->segment_align;
107  off_t offset = 0;
108  ssize_t nread;
109  union
110  {
111    Elf64_auxv_t a64[64];
112    Elf32_auxv_t a32[128];
113  } d;
114  do
115    {
116      eu_static_assert (sizeof d.a64 == sizeof d.a32);
117      nread = pread_retry (fd, d.a64, sizeof d.a64, offset);
118      if (nread < 0)
119	{
120	  int ret = errno;
121	  close (fd);
122	  return ret;
123	}
124      for (size_t a32i = 0; a32i < nread / sizeof d.a32[0]; a32i++)
125	{
126	  const Elf32_auxv_t *a32 = d.a32 + a32i;
127	  switch (a32->a_type)
128	  {
129	    case AT_SYSINFO_EHDR:
130	      sysinfo_ehdr32 = a32->a_un.a_val;
131	      break;
132	    case AT_PAGESZ:
133	      segment_align32 = a32->a_un.a_val;
134	      break;
135	  }
136	}
137      for (size_t a64i = 0; a64i < nread / sizeof d.a64[0]; a64i++)
138	{
139	  const Elf64_auxv_t *a64 = d.a64 + a64i;
140	  switch (a64->a_type)
141	  {
142	    case AT_SYSINFO_EHDR:
143	      sysinfo_ehdr64 = a64->a_un.a_val;
144	      break;
145	    case AT_PAGESZ:
146	      segment_align64 = a64->a_un.a_val;
147	      break;
148	  }
149	}
150      offset += nread;
151    }
152  while (nread == sizeof d.a64);
153
154  close (fd);
155
156  bool valid64 = sysinfo_ehdr64 != 0 || segment_align64 != dwfl->segment_align;
157  bool valid32 = sysinfo_ehdr32 != 0 || segment_align32 != dwfl->segment_align;
158
159  unsigned char pid_class = ELFCLASSNONE;
160  if (valid64 && valid32)
161    pid_class = get_pid_class (pid);
162
163  if (pid_class == ELFCLASS64 || (valid64 && ! valid32))
164    {
165      *sysinfo_ehdr = sysinfo_ehdr64;
166      dwfl->segment_align = segment_align64;
167      return 0;
168    }
169  if (pid_class == ELFCLASS32 || (! valid64 && valid32))
170    {
171      *sysinfo_ehdr = sysinfo_ehdr32;
172      dwfl->segment_align = segment_align32;
173      return 0;
174    }
175  return ENOEXEC;
176}
177
178static inline bool
179do_report (Dwfl *dwfl, char **plast_file, Dwarf_Addr low, Dwarf_Addr high)
180{
181  if (*plast_file != NULL)
182    {
183      Dwfl_Module *mod = INTUSE(dwfl_report_module) (dwfl, *plast_file,
184						     low, high);
185      free (*plast_file);
186      *plast_file = NULL;
187      if (unlikely (mod == NULL))
188        return true;
189    }
190  return false;
191}
192
193#define report() do_report(dwfl, &last_file, low, high)
194
195static int
196proc_maps_report (Dwfl *dwfl, FILE *f, GElf_Addr sysinfo_ehdr, pid_t pid)
197{
198  unsigned int last_dmajor = -1, last_dminor = -1;
199  uint64_t last_ino = -1;
200  char *last_file = NULL;
201  Dwarf_Addr low = 0, high = 0;
202
203  char *line = NULL;
204  size_t linesz;
205  ssize_t len;
206  while ((len = getline (&line, &linesz, f)) > 0)
207    {
208      if (line[len - 1] == '\n')
209	line[len - 1] = '\0';
210
211      Dwarf_Addr start, end, offset;
212      unsigned int dmajor, dminor;
213      uint64_t ino;
214      int nread = -1;
215      if (sscanf (line, "%" PRIx64 "-%" PRIx64 " %*s %" PRIx64
216		  " %x:%x %" PRIi64 " %n",
217		  &start, &end, &offset, &dmajor, &dminor, &ino, &nread) < 6
218	  || nread <= 0)
219	{
220	  free (line);
221	  return ENOEXEC;
222	}
223
224      /* If this is the special mapping AT_SYSINFO_EHDR pointed us at,
225	 report the last one and then this special one.  */
226      if (start == sysinfo_ehdr && start != 0)
227	{
228	  if (report ())
229	    {
230	    bad_report:
231	      free (line);
232	      return -1;
233	    }
234
235	  low = start;
236	  high = end;
237	  if (asprintf (&last_file, "[vdso: %d]", (int) pid) < 0
238	      || report ())
239	    goto bad_report;
240	}
241
242      char *file = line + nread + strspn (line + nread, " \t");
243      if (file[0] != '/' || (ino == 0 && dmajor == 0 && dminor == 0))
244	/* This line doesn't indicate a file mapping.  */
245	continue;
246
247      if (last_file != NULL
248	  && ino == last_ino && dmajor == last_dmajor && dminor == last_dminor)
249	{
250	  /* This is another portion of the same file's mapping.  */
251	  if (strcmp (last_file, file) != 0)
252	    goto bad_report;
253	  high = end;
254	}
255      else
256	{
257	  /* This is a different file mapping.  Report the last one.  */
258	  if (report ())
259	    goto bad_report;
260	  low = start;
261	  high = end;
262	  last_file = strdup (file);
263	  last_ino = ino;
264	  last_dmajor = dmajor;
265	  last_dminor = dminor;
266	}
267    }
268  free (line);
269
270  int result = ferror_unlocked (f) ? errno : feof_unlocked (f) ? 0 : ENOEXEC;
271
272  /* Report the final one.  */
273  bool lose = report ();
274
275  return result != 0 ? result : lose ? -1 : 0;
276}
277
278int
279dwfl_linux_proc_maps_report (Dwfl *dwfl, FILE *f)
280{
281  return proc_maps_report (dwfl, f, 0, 0);
282}
283INTDEF (dwfl_linux_proc_maps_report)
284
285int
286dwfl_linux_proc_report (Dwfl *dwfl, pid_t pid)
287{
288  if (dwfl == NULL)
289    return -1;
290
291  /* We'll notice the AT_SYSINFO_EHDR address specially when we hit it.  */
292  GElf_Addr sysinfo_ehdr = 0;
293  int result = grovel_auxv (pid, dwfl, &sysinfo_ehdr);
294  if (result != 0)
295    return result;
296
297  char *fname;
298  if (asprintf (&fname, PROCMAPSFMT, pid) < 0)
299    return ENOMEM;
300
301  FILE *f = fopen (fname, "r");
302  free (fname);
303  if (f == NULL)
304    return errno;
305
306  (void) __fsetlocking (f, FSETLOCKING_BYCALLER);
307
308  result = proc_maps_report (dwfl, f, sysinfo_ehdr, pid);
309
310  fclose (f);
311
312  return result;
313}
314INTDEF (dwfl_linux_proc_report)
315
316static ssize_t
317read_proc_memory (void *arg, void *data, GElf_Addr address,
318		  size_t minread, size_t maxread)
319{
320  const int fd = *(const int *) arg;
321
322  /* This code relies on the fact the Linux kernel accepts negative
323     offsets when seeking /dev/$$/mem files, as a special case. In
324     particular pread cannot be used here, because it will always
325     return EINVAL when passed a negative offset.  */
326
327  if (lseek (fd, (off_t) address, SEEK_SET) == -1)
328    return -1;
329
330  ssize_t nread = read (fd, data, maxread);
331
332  if (nread > 0 && (size_t) nread < minread)
333    nread = 0;
334  return nread;
335}
336
337extern Elf *elf_from_remote_memory (GElf_Addr ehdr_vma,
338				    GElf_Xword pagesize,
339				    GElf_Addr *loadbasep,
340				    ssize_t (*read_memory) (void *arg,
341							    void *data,
342							    GElf_Addr address,
343							    size_t minread,
344							    size_t maxread),
345				    void *arg);
346
347
348/* Dwfl_Callbacks.find_elf */
349
350int
351dwfl_linux_proc_find_elf (Dwfl_Module *mod __attribute__ ((unused)),
352			  void **userdata __attribute__ ((unused)),
353			  const char *module_name, Dwarf_Addr base,
354			  char **file_name, Elf **elfp)
355{
356  int pid = -1;
357  if (module_name[0] == '/')
358    {
359      /* When this callback is used together with dwfl_linux_proc_report
360	 then we might see mappings of special character devices.  Make
361	 sure we only open and return regular files.  Special devices
362	 might hang on open or read.  (deleted) files are super special.
363	 The image might come from memory if we are attached.  */
364      struct stat sb;
365      if (stat (module_name, &sb) == -1 || (sb.st_mode & S_IFMT) != S_IFREG)
366	{
367	  if (strcmp (strrchr (module_name, ' ') ?: "", " (deleted)") == 0)
368	    pid = INTUSE(dwfl_pid) (mod->dwfl);
369	  else
370	    return -1;
371	}
372
373      if (pid == -1)
374	{
375	  int fd = open (module_name, O_RDONLY);
376	  if (fd >= 0)
377	    {
378	      *file_name = strdup (module_name);
379	      if (*file_name == NULL)
380		{
381		  close (fd);
382		  return ENOMEM;
383		}
384	    }
385	  return fd;
386	}
387    }
388
389  if (pid != -1 || sscanf (module_name, "[vdso: %d]", &pid) == 1)
390    {
391      /* Special case for in-memory ELF image.  */
392
393      bool detach = false;
394      bool tid_was_stopped = false;
395      struct __libdwfl_pid_arg *pid_arg = __libdwfl_get_pid_arg (mod->dwfl);
396      if (pid_arg != NULL && ! pid_arg->assume_ptrace_stopped)
397	{
398	  /* If any thread is already attached we are fine.  Read
399	     through that thread.  It doesn't have to be the main
400	     thread pid.  */
401	  pid_t tid = pid_arg->tid_attached;
402	  if (tid != 0)
403	    pid = tid;
404	  else
405	    detach = __libdwfl_ptrace_attach (pid, &tid_was_stopped);
406	}
407
408      char *fname;
409      if (asprintf (&fname, PROCMEMFMT, pid) < 0)
410	goto detach;
411
412      int fd = open (fname, O_RDONLY);
413      free (fname);
414      if (fd < 0)
415	goto detach;
416
417      *elfp = elf_from_remote_memory (base, getpagesize (), NULL,
418				      &read_proc_memory, &fd);
419
420      close (fd);
421
422      *file_name = NULL;
423
424    detach:
425      if (detach)
426	__libdwfl_ptrace_detach (pid, tid_was_stopped);
427      return -1;
428    }
429
430  return -1;
431}
432INTDEF (dwfl_linux_proc_find_elf)
433