• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
55 static unsigned char
get_pid_class(pid_t pid)56 get_pid_class (pid_t pid)
57 {
58   char *fname;
59   if (asprintf (&fname, PROCEXEFMT, pid) < 0)
60     return ELFCLASSNONE;
61 
62   int fd = open64 (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 
91 static int
grovel_auxv(pid_t pid,Dwfl * dwfl,GElf_Addr * sysinfo_ehdr)92 grovel_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 = open64 (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 
178 static int
proc_maps_report(Dwfl * dwfl,FILE * f,GElf_Addr sysinfo_ehdr,pid_t pid)179 proc_maps_report (Dwfl *dwfl, FILE *f, GElf_Addr sysinfo_ehdr, pid_t pid)
180 {
181   unsigned int last_dmajor = -1, last_dminor = -1;
182   uint64_t last_ino = -1;
183   char *last_file = NULL;
184   Dwarf_Addr low = 0, high = 0;
185 
186   inline bool report (void)
187     {
188       if (last_file != NULL)
189 	{
190 	  Dwfl_Module *mod = INTUSE(dwfl_report_module) (dwfl, last_file,
191 							 low, high);
192 	  free (last_file);
193 	  last_file = NULL;
194 	  if (unlikely (mod == NULL))
195 	    return true;
196 	}
197       return false;
198     }
199 
200   char *line = NULL;
201   size_t linesz;
202   ssize_t len;
203   while ((len = getline (&line, &linesz, f)) > 0)
204     {
205       if (line[len - 1] == '\n')
206 	line[len - 1] = '\0';
207 
208       Dwarf_Addr start, end, offset;
209       unsigned int dmajor, dminor;
210       uint64_t ino;
211       int nread = -1;
212       if (sscanf (line, "%" PRIx64 "-%" PRIx64 " %*s %" PRIx64
213 		  " %x:%x %" PRIi64 " %n",
214 		  &start, &end, &offset, &dmajor, &dminor, &ino, &nread) < 6
215 	  || nread <= 0)
216 	{
217 	  free (line);
218 	  return ENOEXEC;
219 	}
220 
221       /* If this is the special mapping AT_SYSINFO_EHDR pointed us at,
222 	 report the last one and then this special one.  */
223       if (start == sysinfo_ehdr && start != 0)
224 	{
225 	  if (report ())
226 	    {
227 	    bad_report:
228 	      free (line);
229 	      return -1;
230 	    }
231 
232 	  low = start;
233 	  high = end;
234 	  if (asprintf (&last_file, "[vdso: %d]", (int) pid) < 0
235 	      || report ())
236 	    goto bad_report;
237 	}
238 
239       char *file = line + nread + strspn (line + nread, " \t");
240       if (file[0] != '/' || (ino == 0 && dmajor == 0 && dminor == 0))
241 	/* This line doesn't indicate a file mapping.  */
242 	continue;
243 
244       if (last_file != NULL
245 	  && ino == last_ino && dmajor == last_dmajor && dminor == last_dminor)
246 	{
247 	  /* This is another portion of the same file's mapping.  */
248 	  if (strcmp (last_file, file) != 0)
249 	    goto bad_report;
250 	  high = end;
251 	}
252       else
253 	{
254 	  /* This is a different file mapping.  Report the last one.  */
255 	  if (report ())
256 	    goto bad_report;
257 	  low = start;
258 	  high = end;
259 	  last_file = strdup (file);
260 	  last_ino = ino;
261 	  last_dmajor = dmajor;
262 	  last_dminor = dminor;
263 	}
264     }
265   free (line);
266 
267   int result = ferror_unlocked (f) ? errno : feof_unlocked (f) ? 0 : ENOEXEC;
268 
269   /* Report the final one.  */
270   bool lose = report ();
271 
272   return result != 0 ? result : lose ? -1 : 0;
273 }
274 
275 int
dwfl_linux_proc_maps_report(Dwfl * dwfl,FILE * f)276 dwfl_linux_proc_maps_report (Dwfl *dwfl, FILE *f)
277 {
278   return proc_maps_report (dwfl, f, 0, 0);
279 }
INTDEF(dwfl_linux_proc_maps_report)280 INTDEF (dwfl_linux_proc_maps_report)
281 
282 int
283 dwfl_linux_proc_report (Dwfl *dwfl, pid_t pid)
284 {
285   if (dwfl == NULL)
286     return -1;
287 
288   /* We'll notice the AT_SYSINFO_EHDR address specially when we hit it.  */
289   GElf_Addr sysinfo_ehdr = 0;
290   int result = grovel_auxv (pid, dwfl, &sysinfo_ehdr);
291   if (result != 0)
292     return result;
293 
294   char *fname;
295   if (asprintf (&fname, PROCMAPSFMT, pid) < 0)
296     return ENOMEM;
297 
298   FILE *f = fopen (fname, "r");
299   free (fname);
300   if (f == NULL)
301     return errno;
302 
303   (void) __fsetlocking (f, FSETLOCKING_BYCALLER);
304 
305   result = proc_maps_report (dwfl, f, sysinfo_ehdr, pid);
306 
307   fclose (f);
308 
309   return result;
310 }
INTDEF(dwfl_linux_proc_report)311 INTDEF (dwfl_linux_proc_report)
312 
313 static ssize_t
314 read_proc_memory (void *arg, void *data, GElf_Addr address,
315 		  size_t minread, size_t maxread)
316 {
317   const int fd = *(const int *) arg;
318   ssize_t nread = pread64 (fd, data, maxread, (off64_t) address);
319   /* Some kernels don't actually let us do this read, ignore those errors.  */
320   if (nread < 0 && (errno == EINVAL || errno == EPERM))
321     return 0;
322   if (nread > 0 && (size_t) nread < minread)
323     nread = 0;
324   return nread;
325 }
326 
327 extern Elf *elf_from_remote_memory (GElf_Addr ehdr_vma,
328 				    GElf_Xword pagesize,
329 				    GElf_Addr *loadbasep,
330 				    ssize_t (*read_memory) (void *arg,
331 							    void *data,
332 							    GElf_Addr address,
333 							    size_t minread,
334 							    size_t maxread),
335 				    void *arg);
336 
337 
338 /* Dwfl_Callbacks.find_elf */
339 
340 int
dwfl_linux_proc_find_elf(Dwfl_Module * mod,void ** userdata,const char * module_name,Dwarf_Addr base,char ** file_name,Elf ** elfp)341 dwfl_linux_proc_find_elf (Dwfl_Module *mod __attribute__ ((unused)),
342 			  void **userdata __attribute__ ((unused)),
343 			  const char *module_name, Dwarf_Addr base,
344 			  char **file_name, Elf **elfp)
345 {
346   int pid = -1;
347   if (module_name[0] == '/')
348     {
349       /* When this callback is used together with dwfl_linux_proc_report
350 	 then we might see mappings of special character devices.  Make
351 	 sure we only open and return regular files.  Special devices
352 	 might hang on open or read.  (deleted) files are super special.
353 	 The image might come from memory if we are attached.  */
354       struct stat sb;
355       if (stat (module_name, &sb) == -1 || (sb.st_mode & S_IFMT) != S_IFREG)
356 	{
357 	  if (strcmp (strrchr (module_name, ' ') ?: "", " (deleted)") == 0)
358 	    pid = INTUSE(dwfl_pid) (mod->dwfl);
359 	  else
360 	    return -1;
361 	}
362 
363       if (pid == -1)
364 	{
365 	  int fd = open64 (module_name, O_RDONLY);
366 	  if (fd >= 0)
367 	    {
368 	      *file_name = strdup (module_name);
369 	      if (*file_name == NULL)
370 		{
371 		  close (fd);
372 		  return ENOMEM;
373 		}
374 	    }
375 	  return fd;
376 	}
377     }
378 
379   if (pid != -1 || sscanf (module_name, "[vdso: %d]", &pid) == 1)
380     {
381       /* Special case for in-memory ELF image.  */
382 
383       bool detach = false;
384       bool tid_was_stopped = false;
385       struct __libdwfl_pid_arg *pid_arg = __libdwfl_get_pid_arg (mod->dwfl);
386       if (pid_arg != NULL && ! pid_arg->assume_ptrace_stopped)
387 	{
388 	  /* If any thread is already attached we are fine.  Read
389 	     through that thread.  It doesn't have to be the main
390 	     thread pid.  */
391 	  pid_t tid = pid_arg->tid_attached;
392 	  if (tid != 0)
393 	    pid = tid;
394 	  else
395 	    detach = __libdwfl_ptrace_attach (pid, &tid_was_stopped);
396 	}
397 
398       char *fname;
399       if (asprintf (&fname, PROCMEMFMT, pid) < 0)
400 	goto detach;
401 
402       int fd = open64 (fname, O_RDONLY);
403       free (fname);
404       if (fd < 0)
405 	goto detach;
406 
407       *elfp = elf_from_remote_memory (base, getpagesize (), NULL,
408 				      &read_proc_memory, &fd);
409 
410       close (fd);
411 
412       *file_name = NULL;
413 
414     detach:
415       if (detach)
416 	__libdwfl_ptrace_detach (pid, tid_was_stopped);
417       return -1;
418     }
419 
420   return -1;
421 }
422 INTDEF (dwfl_linux_proc_find_elf)
423