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