]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libproc/proc_sym.c
MFV: Import atf-0.21.
[FreeBSD/FreeBSD.git] / lib / libproc / proc_sym.c
1 /*-
2  * Copyright (c) 2010 The FreeBSD Foundation
3  * Copyright (c) 2008 John Birrell (jb@freebsd.org)
4  * All rights reserved.
5  *
6  * Portions of this software were developed by Rui Paulo under sponsorship
7  * from the FreeBSD Foundation.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33
34 #include <sys/types.h>
35 #ifndef NO_CTF
36 #include <sys/ctf.h>
37 #include <sys/ctf_api.h>
38 #endif
39 #include <sys/user.h>
40
41 #include <assert.h>
42 #include <err.h>
43 #include <fcntl.h>
44 #include <libgen.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <unistd.h>
49 #ifndef NO_CTF
50 #include <libctf.h>
51 #endif
52 #include <libutil.h>
53
54 #include "_libproc.h"
55
56 #ifdef NO_CTF
57 typedef struct ctf_file ctf_file_t;
58 #endif
59
60 #ifndef NO_CXA_DEMANGLE
61 extern char *__cxa_demangle(const char *, char *, size_t *, int *);
62 #endif /* NO_CXA_DEMANGLE */
63
64 static void     proc_rdl2prmap(rd_loadobj_t *, prmap_t *);
65
66 static void
67 demangle(const char *symbol, char *buf, size_t len)
68 {
69 #ifndef NO_CXA_DEMANGLE
70         char *dembuf;
71
72         if (symbol[0] == '_' && symbol[1] == 'Z' && symbol[2]) {
73                 dembuf = __cxa_demangle(symbol, NULL, NULL, NULL);
74                 if (!dembuf)
75                         goto fail;
76                 strlcpy(buf, dembuf, len);
77                 free(dembuf);
78                 return;
79         }
80 fail:
81 #endif /* NO_CXA_DEMANGLE */
82         strlcpy(buf, symbol, len);
83 }
84
85 static void
86 proc_rdl2prmap(rd_loadobj_t *rdl, prmap_t *map)
87 {
88         map->pr_vaddr = rdl->rdl_saddr;
89         map->pr_size = rdl->rdl_eaddr - rdl->rdl_saddr;
90         map->pr_offset = rdl->rdl_offset;
91         map->pr_mflags = 0;
92         if (rdl->rdl_prot & RD_RDL_R)
93                 map->pr_mflags |= MA_READ;
94         if (rdl->rdl_prot & RD_RDL_W)
95                 map->pr_mflags |= MA_WRITE;
96         if (rdl->rdl_prot & RD_RDL_X)
97                 map->pr_mflags |= MA_EXEC;
98         strlcpy(map->pr_mapname, rdl->rdl_path,
99             sizeof(map->pr_mapname));
100 }
101
102 char *
103 proc_objname(struct proc_handle *p, uintptr_t addr, char *objname,
104     size_t objnamesz)
105 {
106         size_t i;
107         rd_loadobj_t *rdl;
108
109         for (i = 0; i < p->nobjs; i++) {
110                 rdl = &p->rdobjs[i];
111                 if (addr >= rdl->rdl_saddr && addr < rdl->rdl_eaddr) {
112                         strlcpy(objname, rdl->rdl_path, objnamesz);
113                         return (objname);
114                 }
115         }
116         return (NULL);
117 }
118
119 prmap_t *
120 proc_obj2map(struct proc_handle *p, const char *objname)
121 {
122         size_t i;
123         prmap_t *map;
124         rd_loadobj_t *rdl;
125         char path[MAXPATHLEN];
126
127         rdl = NULL;
128         for (i = 0; i < p->nobjs; i++) {
129                 basename_r(p->rdobjs[i].rdl_path, path);
130                 if (strcmp(path, objname) == 0) {
131                         rdl = &p->rdobjs[i];
132                         break;
133                 }
134         }
135         if (rdl == NULL) {
136                 if (strcmp(objname, "a.out") == 0 && p->rdexec != NULL)
137                         rdl = p->rdexec;
138                 else
139                         return (NULL);
140         }
141
142         if ((map = malloc(sizeof(*map))) == NULL)
143                 return (NULL);
144         proc_rdl2prmap(rdl, map);
145         return (map);
146 }
147
148 int
149 proc_iter_objs(struct proc_handle *p, proc_map_f *func, void *cd)
150 {
151         size_t i;
152         rd_loadobj_t *rdl;
153         prmap_t map;
154         char path[MAXPATHLEN];
155         char last[MAXPATHLEN];
156
157         if (p->nobjs == 0)
158                 return (-1);
159         memset(last, 0, sizeof(last));
160         for (i = 0; i < p->nobjs; i++) {
161                 rdl = &p->rdobjs[i];
162                 proc_rdl2prmap(rdl, &map);
163                 basename_r(rdl->rdl_path, path);
164                 /*
165                  * We shouldn't call the callback twice with the same object.
166                  * To do that we are assuming the fact that if there are
167                  * repeated object names (i.e. different mappings for the
168                  * same object) they occur next to each other.
169                  */
170                 if (strcmp(path, last) == 0)
171                         continue;
172                 (*func)(cd, &map, path);
173                 strlcpy(last, path, sizeof(last));
174         }
175
176         return (0);
177 }
178
179 prmap_t *
180 proc_addr2map(struct proc_handle *p, uintptr_t addr)
181 {
182         size_t i;
183         int cnt, lastvn = 0;
184         prmap_t *map;
185         rd_loadobj_t *rdl;
186         struct kinfo_vmentry *kves, *kve;
187
188         /*
189          * If we don't have a cache of listed objects, we need to query
190          * it ourselves.
191          */
192         if (p->nobjs == 0) {
193                 if ((kves = kinfo_getvmmap(p->pid, &cnt)) == NULL)
194                         return (NULL);
195                 for (i = 0; i < (size_t)cnt; i++) {
196                         kve = kves + i;
197                         if (kve->kve_type == KVME_TYPE_VNODE)
198                                 lastvn = i;
199                         if (addr >= kve->kve_start && addr < kve->kve_end) {
200                                 if ((map = malloc(sizeof(*map))) == NULL) {
201                                         free(kves);
202                                         return (NULL);
203                                 }
204                                 map->pr_vaddr = kve->kve_start;
205                                 map->pr_size = kve->kve_end - kve->kve_start;
206                                 map->pr_offset = kve->kve_offset;
207                                 map->pr_mflags = 0;
208                                 if (kve->kve_protection & KVME_PROT_READ)
209                                         map->pr_mflags |= MA_READ;
210                                 if (kve->kve_protection & KVME_PROT_WRITE)
211                                         map->pr_mflags |= MA_WRITE;
212                                 if (kve->kve_protection & KVME_PROT_EXEC)
213                                         map->pr_mflags |= MA_EXEC;
214                                 if (kve->kve_flags & KVME_FLAG_COW)
215                                         map->pr_mflags |= MA_COW;
216                                 if (kve->kve_flags & KVME_FLAG_NEEDS_COPY)
217                                         map->pr_mflags |= MA_NEEDS_COPY;
218                                 if (kve->kve_flags & KVME_FLAG_NOCOREDUMP)
219                                         map->pr_mflags |= MA_NOCOREDUMP;
220                                 strlcpy(map->pr_mapname, kves[lastvn].kve_path,
221                                     sizeof(map->pr_mapname));
222                                 free(kves);
223                                 return (map);
224                         }
225                 }
226                 free(kves);
227                 return (NULL);
228         }
229
230         for (i = 0; i < p->nobjs; i++) {
231                 rdl = &p->rdobjs[i];
232                 if (addr >= rdl->rdl_saddr && addr < rdl->rdl_eaddr) {
233                         if ((map = malloc(sizeof(*map))) == NULL)
234                                 return (NULL);
235                         proc_rdl2prmap(rdl, map);
236                         return (map);
237                 }
238         }
239         return (NULL);
240 }
241
242 /*
243  * Look up the symbol at addr, returning a copy of the symbol and its name.
244  */
245 static int
246 lookup_addr(Elf *e, Elf_Scn *scn, u_long stridx, uintptr_t off, uintptr_t addr,
247     const char **name, GElf_Sym *symcopy)
248 {
249         GElf_Sym sym;
250         Elf_Data *data;
251         const char *s;
252         uint64_t rsym;
253         int i;
254
255         if ((data = elf_getdata(scn, NULL)) == NULL) {
256                 DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1));
257                 return (1);
258         }
259         for (i = 0; gelf_getsym(data, i, &sym) != NULL; i++) {
260                 rsym = off + sym.st_value;
261                 if (addr >= rsym && addr < rsym + sym.st_size) {
262                         s = elf_strptr(e, stridx, sym.st_name);
263                         if (s != NULL) {
264                                 *name = s;
265                                 memcpy(symcopy, &sym, sizeof(*symcopy));
266                                 /*
267                                  * DTrace expects the st_value to contain
268                                  * only the address relative to the start of
269                                  * the function.
270                                  */
271                                 symcopy->st_value = rsym;
272                                 return (0);
273                         }
274                 }
275         }
276         return (1);
277 }
278
279 int
280 proc_addr2sym(struct proc_handle *p, uintptr_t addr, char *name,
281     size_t namesz, GElf_Sym *symcopy)
282 {
283         GElf_Ehdr ehdr;
284         GElf_Shdr shdr;
285         Elf *e;
286         Elf_Scn *scn, *dynsymscn = NULL, *symtabscn = NULL;
287         prmap_t *map;
288         const char *s;
289         uintptr_t off;
290         u_long symtabstridx = 0, dynsymstridx = 0;
291         int fd, error = -1;
292
293         if ((map = proc_addr2map(p, addr)) == NULL)
294                 return (-1);
295         if ((fd = open(map->pr_mapname, O_RDONLY, 0)) < 0) {
296                 DPRINTF("ERROR: open %s failed", map->pr_mapname);
297                 goto err0;
298         }
299         if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
300                 DPRINTFX("ERROR: elf_begin() failed: %s", elf_errmsg(-1));
301                 goto err1;
302         }
303         if (gelf_getehdr(e, &ehdr) == NULL) {
304                 DPRINTFX("ERROR: gelf_getehdr() failed: %s", elf_errmsg(-1));
305                 goto err2;
306         }
307
308         /*
309          * Find the index of the STRTAB and SYMTAB sections to locate
310          * symbol names.
311          */
312         scn = NULL;
313         while ((scn = elf_nextscn(e, scn)) != NULL) {
314                 gelf_getshdr(scn, &shdr);
315                 switch (shdr.sh_type) {
316                 case SHT_SYMTAB:
317                         symtabscn = scn;
318                         symtabstridx = shdr.sh_link;
319                         break;
320                 case SHT_DYNSYM:
321                         dynsymscn = scn;
322                         dynsymstridx = shdr.sh_link;
323                         break;
324                 }
325         }
326
327         off = ehdr.e_type == ET_EXEC ? 0 : map->pr_vaddr;
328
329         /*
330          * First look up the symbol in the dynsymtab, and fall back to the
331          * symtab if the lookup fails.
332          */
333         error = lookup_addr(e, dynsymscn, dynsymstridx, off, addr, &s, symcopy);
334         if (error == 0)
335                 goto out;
336
337         error = lookup_addr(e, symtabscn, symtabstridx, off, addr, &s, symcopy);
338         if (error == 0)
339                 goto out;
340
341 out:
342         demangle(s, name, namesz);
343 err2:
344         elf_end(e);
345 err1:
346         close(fd);
347 err0:
348         free(map);
349         return (error);
350 }
351
352 prmap_t *
353 proc_name2map(struct proc_handle *p, const char *name)
354 {
355         size_t i;
356         int cnt;
357         prmap_t *map = NULL;
358         char tmppath[MAXPATHLEN];
359         struct kinfo_vmentry *kves, *kve;
360         rd_loadobj_t *rdl;
361
362         /*
363          * If we haven't iterated over the list of loaded objects,
364          * librtld_db isn't yet initialized and it's very likely
365          * that librtld_db called us. We need to do the heavy
366          * lifting here to find the symbol librtld_db is looking for.
367          */
368         if (p->nobjs == 0) {
369                 if ((kves = kinfo_getvmmap(proc_getpid(p), &cnt)) == NULL)
370                         return (NULL);
371                 for (i = 0; i < (size_t)cnt; i++) {
372                         kve = kves + i;
373                         basename_r(kve->kve_path, tmppath);
374                         if (strcmp(tmppath, name) == 0) {
375                                 map = proc_addr2map(p, kve->kve_start);
376                                 break;
377                         }
378                 }
379                 free(kves);
380         } else
381                 for (i = 0; i < p->nobjs; i++) {
382                         rdl = &p->rdobjs[i];
383                         basename_r(rdl->rdl_path, tmppath);
384                         if (strcmp(tmppath, name) == 0) {
385                                 if ((map = malloc(sizeof(*map))) == NULL)
386                                         return (NULL);
387                                 proc_rdl2prmap(rdl, map);
388                                 break;
389                         }
390                 }
391
392         if (map == NULL && strcmp(name, "a.out") == 0 && p->rdexec != NULL)
393                 map = proc_addr2map(p, p->rdexec->rdl_saddr);
394
395         return (map);
396 }
397
398 /*
399  * Look up the symbol with the given name and return a copy of it.
400  */
401 static int
402 lookup_name(Elf *e, Elf_Scn *scn, u_long stridx, const char *symbol,
403     GElf_Sym *symcopy, prsyminfo_t *si)
404 {
405         GElf_Sym sym;
406         Elf_Data *data;
407         char *s;
408         int i;
409
410         if ((data = elf_getdata(scn, NULL)) == NULL) {
411                 DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1));
412                 return (1);
413         }
414         for (i = 0; gelf_getsym(data, i, &sym) != NULL; i++) {
415                 s = elf_strptr(e, stridx, sym.st_name);
416                 if (s != NULL && strcmp(s, symbol) == 0) {
417                         memcpy(symcopy, &sym, sizeof(*symcopy));
418                         if (si != NULL)
419                                 si->prs_id = i;
420                         return (0);
421                 }
422         }
423         return (1);
424 }
425
426 int
427 proc_name2sym(struct proc_handle *p, const char *object, const char *symbol,
428     GElf_Sym *symcopy, prsyminfo_t *si)
429 {
430         Elf *e;
431         Elf_Scn *scn, *dynsymscn = NULL, *symtabscn = NULL;
432         GElf_Shdr shdr;
433         GElf_Ehdr ehdr;
434         prmap_t *map;
435         uintptr_t off;
436         u_long symtabstridx = 0, dynsymstridx = 0;
437         int fd, error = -1;
438
439         if ((map = proc_name2map(p, object)) == NULL) {
440                 DPRINTFX("ERROR: couldn't find object %s", object);
441                 goto err0;
442         }
443         if ((fd = open(map->pr_mapname, O_RDONLY, 0)) < 0) {
444                 DPRINTF("ERROR: open %s failed", map->pr_mapname);
445                 goto err0;
446         }
447         if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
448                 DPRINTFX("ERROR: elf_begin() failed: %s", elf_errmsg(-1));
449                 goto err1;
450         }
451         if (gelf_getehdr(e, &ehdr) == NULL) {
452                 DPRINTFX("ERROR: gelf_getehdr() failed: %s", elf_errmsg(-1));
453                 goto err2;
454         }
455         /*
456          * Find the index of the STRTAB and SYMTAB sections to locate
457          * symbol names.
458          */
459         scn = NULL;
460         while ((scn = elf_nextscn(e, scn)) != NULL) {
461                 gelf_getshdr(scn, &shdr);
462                 switch (shdr.sh_type) {
463                 case SHT_SYMTAB:
464                         symtabscn = scn;
465                         symtabstridx = shdr.sh_link;
466                         break;
467                 case SHT_DYNSYM:
468                         dynsymscn = scn;
469                         dynsymstridx = shdr.sh_link;
470                         break;
471                 }
472         }
473
474         /*
475          * First look up the symbol in the dynsymtab, and fall back to the
476          * symtab if the lookup fails.
477          */
478         error = lookup_name(e, dynsymscn, dynsymstridx, symbol, symcopy, si);
479         if (error == 0)
480                 goto out;
481
482         error = lookup_name(e, symtabscn, symtabstridx, symbol, symcopy, si);
483         if (error == 0)
484                 goto out;
485
486 out:
487         off = ehdr.e_type == ET_EXEC ? 0 : map->pr_vaddr;
488         symcopy->st_value += off;
489
490 err2:
491         elf_end(e);
492 err1:
493         close(fd);
494 err0:
495         free(map);
496
497         return (error);
498 }
499
500 ctf_file_t *
501 proc_name2ctf(struct proc_handle *p, const char *name)
502 {
503 #ifndef NO_CTF
504         prmap_t *map;
505         int error;
506
507         if ((map = proc_name2map(p, name)) == NULL)
508                 return (NULL);
509
510         return (ctf_open(map->pr_mapname, &error));
511 #else
512         (void)p;
513         (void)name;
514         return (NULL);
515 #endif
516 }
517
518 int
519 proc_iter_symbyaddr(struct proc_handle *p, const char *object, int which,
520     int mask, proc_sym_f *func, void *cd)
521 {
522         Elf *e;
523         int i, fd;
524         prmap_t *map;
525         Elf_Scn *scn, *foundscn = NULL;
526         Elf_Data *data;
527         GElf_Ehdr ehdr;
528         GElf_Shdr shdr;
529         GElf_Sym sym;
530         unsigned long stridx = -1;
531         char *s;
532         int error = -1;
533
534         if ((map = proc_name2map(p, object)) == NULL)
535                 return (-1);
536         if ((fd = open(map->pr_mapname, O_RDONLY)) < 0) {
537                 DPRINTF("ERROR: open %s failed", map->pr_mapname);
538                 goto err0;
539         }
540         if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
541                 DPRINTFX("ERROR: elf_begin() failed: %s", elf_errmsg(-1));
542                 goto err1;
543         }
544         if (gelf_getehdr(e, &ehdr) == NULL) {
545                 DPRINTFX("ERROR: gelf_getehdr() failed: %s", elf_errmsg(-1));
546                 goto err2;
547         }
548         /*
549          * Find the section we are looking for.
550          */
551         scn = NULL;
552         while ((scn = elf_nextscn(e, scn)) != NULL) {
553                 gelf_getshdr(scn, &shdr);
554                 if (which == PR_SYMTAB &&
555                     shdr.sh_type == SHT_SYMTAB) {
556                         foundscn = scn;
557                         break;
558                 } else if (which == PR_DYNSYM &&
559                     shdr.sh_type == SHT_DYNSYM) {
560                         foundscn = scn;
561                         break;
562                 }
563         }
564         if (!foundscn)
565                 return (-1);
566         stridx = shdr.sh_link;
567         if ((data = elf_getdata(foundscn, NULL)) == NULL) {
568                 DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1));
569                 goto err2;
570         }
571         for (i = 0; gelf_getsym(data, i, &sym) != NULL; i++) {
572                 if (GELF_ST_BIND(sym.st_info) == STB_LOCAL &&
573                     (mask & BIND_LOCAL) == 0)
574                         continue;
575                 if (GELF_ST_BIND(sym.st_info) == STB_GLOBAL &&
576                     (mask & BIND_GLOBAL) == 0)
577                         continue;
578                 if (GELF_ST_BIND(sym.st_info) == STB_WEAK &&
579                     (mask & BIND_WEAK) == 0)
580                         continue;
581                 if (GELF_ST_TYPE(sym.st_info) == STT_NOTYPE &&
582                     (mask & TYPE_NOTYPE) == 0)
583                         continue;
584                 if (GELF_ST_TYPE(sym.st_info) == STT_OBJECT &&
585                     (mask & TYPE_OBJECT) == 0)
586                         continue;
587                 if (GELF_ST_TYPE(sym.st_info) == STT_FUNC &&
588                     (mask & TYPE_FUNC) == 0)
589                         continue;
590                 if (GELF_ST_TYPE(sym.st_info) == STT_SECTION &&
591                     (mask & TYPE_SECTION) == 0)
592                         continue;
593                 if (GELF_ST_TYPE(sym.st_info) == STT_FILE &&
594                     (mask & TYPE_FILE) == 0)
595                         continue;
596                 s = elf_strptr(e, stridx, sym.st_name);
597                 if (ehdr.e_type != ET_EXEC)
598                         sym.st_value += map->pr_vaddr;
599                 (*func)(cd, &sym, s);
600         }
601         error = 0;
602 err2:
603         elf_end(e);
604 err1:
605         close(fd);
606 err0:
607         free(map);
608         return (error);
609 }