Imported Upstream version 0.160
[platform/upstream/elfutils.git] / libdwfl / linux-proc-maps.c
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
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
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
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
276 dwfl_linux_proc_maps_report (Dwfl *dwfl, FILE *f)
277 {
278   return proc_maps_report (dwfl, f, 0, 0);
279 }
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 }
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
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)