In copyright statement correct that the author is me, not Bill Paul.
[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  * $FreeBSD$
31  */
32
33 #include <sys/types.h>
34 #include <sys/user.h>
35
36 #include <assert.h>
37 #include <err.h>
38 #include <stdio.h>
39 #include <libgen.h>
40 #include <string.h>
41 #include <stdlib.h>
42 #include <fcntl.h>
43 #include <string.h>
44 #include <unistd.h>
45 #include <libutil.h>
46
47 #include "_libproc.h"
48
49 #ifndef NO_CXA_DEMANGLE
50 extern char *__cxa_demangle(const char *, char *, size_t *, int *);
51 #endif /* NO_CXA_DEMANGLE */
52
53 static void     proc_rdl2prmap(rd_loadobj_t *, prmap_t *);
54
55 static void
56 demangle(const char *symbol, char *buf, size_t len)
57 {
58 #ifndef NO_CXA_DEMANGLE
59         char *dembuf;
60         size_t demlen;
61
62         if (symbol[0] == '_' && symbol[1] == 'Z' && symbol[2]) {
63                 dembuf = malloc(len);
64                 if (!dembuf)
65                         goto fail;
66                 demlen = len;
67                 dembuf = __cxa_demangle(symbol, dembuf, &demlen, NULL);
68                 if (!dembuf)
69                         goto fail;
70                 strlcpy(buf, dembuf, len);
71                 free(dembuf);
72         }
73
74         return;
75 fail:
76 #endif /* NO_CXA_DEMANGLE */
77         strlcpy(buf, symbol, len);
78 }
79
80 static void
81 proc_rdl2prmap(rd_loadobj_t *rdl, prmap_t *map)
82 {
83         map->pr_vaddr = rdl->rdl_saddr;
84         map->pr_size = rdl->rdl_eaddr - rdl->rdl_saddr;
85         map->pr_offset = rdl->rdl_offset;
86         map->pr_mflags = 0;
87         if (rdl->rdl_prot & RD_RDL_R)
88                 map->pr_mflags |= MA_READ;
89         if (rdl->rdl_prot & RD_RDL_W)
90                 map->pr_mflags |= MA_WRITE;
91         if (rdl->rdl_prot & RD_RDL_X)
92                 map->pr_mflags |= MA_EXEC;
93         strlcpy(map->pr_mapname, rdl->rdl_path,
94             sizeof(map->pr_mapname));
95 }
96
97 char *
98 proc_objname(struct proc_handle *p, uintptr_t addr, char *objname,
99     size_t objnamesz)
100 {
101         size_t i;
102         rd_loadobj_t *rdl;
103
104         for (i = 0; i < p->nobjs; i++) {
105                 rdl = &p->rdobjs[i];
106                 if (addr >= rdl->rdl_saddr && addr < rdl->rdl_eaddr) {
107                         strlcpy(objname, rdl->rdl_path, objnamesz);
108                         return (objname);
109                 }
110         }
111         return (NULL);
112 }
113
114 prmap_t *
115 proc_obj2map(struct proc_handle *p, const char *objname)
116 {
117         size_t i;
118         prmap_t *map;
119         rd_loadobj_t *rdl;
120         char path[MAXPATHLEN];
121
122         rdl = NULL;
123         for (i = 0; i < p->nobjs; i++) {
124                 basename_r(p->rdobjs[i].rdl_path, path);
125                 if (strcmp(path, objname) == 0) {
126                         rdl = &p->rdobjs[i];
127                         break;
128                 }
129         }
130         if (rdl == NULL && strcmp(objname, "a.out") == 0 && p->rdexec != NULL)
131                 rdl = p->rdexec;
132         else
133                 return (NULL);
134
135         if ((map = malloc(sizeof(*map))) == NULL)
136                 return (NULL);
137         proc_rdl2prmap(rdl, map);
138         return (map);
139 }
140
141 int
142 proc_iter_objs(struct proc_handle *p, proc_map_f *func, void *cd)
143 {
144         size_t i;
145         rd_loadobj_t *rdl;
146         prmap_t map;
147         char path[MAXPATHLEN];
148         char last[MAXPATHLEN];
149
150         if (p->nobjs == 0)
151                 return (-1);
152         memset(last, 0, sizeof(last));
153         for (i = 0; i < p->nobjs; i++) {
154                 rdl = &p->rdobjs[i];
155                 proc_rdl2prmap(rdl, &map);
156                 basename_r(rdl->rdl_path, path);
157                 /*
158                  * We shouldn't call the callback twice with the same object.
159                  * To do that we are assuming the fact that if there are
160                  * repeated object names (i.e. different mappings for the
161                  * same object) they occur next to each other.
162                  */
163                 if (strcmp(path, last) == 0)
164                         continue;
165                 (*func)(cd, &map, path);
166                 strlcpy(last, path, sizeof(last));
167         }
168
169         return (0);
170 }
171
172 prmap_t *
173 proc_addr2map(struct proc_handle *p, uintptr_t addr)
174 {
175         size_t i;
176         int cnt, lastvn = 0;
177         prmap_t *map;
178         rd_loadobj_t *rdl;
179         struct kinfo_vmentry *kves, *kve;
180
181         /*
182          * If we don't have a cache of listed objects, we need to query
183          * it ourselves.
184          */
185         if (p->nobjs == 0) {
186                 if ((kves = kinfo_getvmmap(p->pid, &cnt)) == NULL)
187                         return (NULL);
188                 for (i = 0; i < (size_t)cnt; i++) {
189                         kve = kves + i;
190                         if (kve->kve_type == KVME_TYPE_VNODE)
191                                 lastvn = i;
192                         if (addr >= kve->kve_start && addr < kve->kve_end) {
193                                 if ((map = malloc(sizeof(*map))) == NULL) {
194                                         free(kves);
195                                         return (NULL);
196                                 }
197                                 map->pr_vaddr = kve->kve_start;
198                                 map->pr_size = kve->kve_end - kve->kve_start;
199                                 map->pr_offset = kve->kve_offset;
200                                 map->pr_mflags = 0;
201                                 if (kve->kve_protection & KVME_PROT_READ)
202                                         map->pr_mflags |= MA_READ;
203                                 if (kve->kve_protection & KVME_PROT_WRITE)
204                                         map->pr_mflags |= MA_WRITE;
205                                 if (kve->kve_protection & KVME_PROT_EXEC)
206                                         map->pr_mflags |= MA_EXEC;
207                                 if (kve->kve_flags & KVME_FLAG_COW)
208                                         map->pr_mflags |= MA_COW;
209                                 if (kve->kve_flags & KVME_FLAG_NEEDS_COPY)
210                                         map->pr_mflags |= MA_NEEDS_COPY;
211                                 if (kve->kve_flags & KVME_FLAG_NOCOREDUMP)
212                                         map->pr_mflags |= MA_NOCOREDUMP;
213                                 strlcpy(map->pr_mapname, kves[lastvn].kve_path,
214                                     sizeof(map->pr_mapname));
215                                 free(kves);
216                                 return (map);
217                         }
218                 }
219                 free(kves);
220                 return (NULL);
221         }
222
223         for (i = 0; i < p->nobjs; i++) {
224                 rdl = &p->rdobjs[i];
225                 if (addr >= rdl->rdl_saddr && addr < rdl->rdl_eaddr) {
226                         if ((map = malloc(sizeof(*map))) == NULL)
227                                 return (NULL);
228                         proc_rdl2prmap(rdl, map);
229                         return (map);
230                 }
231         }
232         return (NULL);
233 }
234
235 int
236 proc_addr2sym(struct proc_handle *p, uintptr_t addr, char *name,
237     size_t namesz, GElf_Sym *symcopy)
238 {
239         Elf *e;
240         Elf_Scn *scn, *dynsymscn = NULL, *symtabscn = NULL;
241         Elf_Data *data;
242         GElf_Shdr shdr;
243         GElf_Sym sym;
244         GElf_Ehdr ehdr;
245         int fd, error = -1;
246         size_t i;
247         uint64_t rsym;
248         prmap_t *map;
249         char *s;
250         unsigned long symtabstridx = 0, dynsymstridx = 0;
251
252         if ((map = proc_addr2map(p, addr)) == NULL)
253                 return (-1);
254         if ((fd = open(map->pr_mapname, O_RDONLY, 0)) < 0) {
255                 DPRINTF("ERROR: open %s failed", map->pr_mapname);
256                 goto err0;
257         }
258         if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
259                 DPRINTFX("ERROR: elf_begin() failed: %s", elf_errmsg(-1));
260                 goto err1;
261         }
262         if (gelf_getehdr(e, &ehdr) == NULL) {
263                 DPRINTFX("ERROR: gelf_getehdr() failed: %s", elf_errmsg(-1));
264                 goto err2;
265         }
266         /*
267          * Find the index of the STRTAB and SYMTAB sections to locate
268          * symbol names.
269          */
270         scn = NULL;
271         while ((scn = elf_nextscn(e, scn)) != NULL) {
272                 gelf_getshdr(scn, &shdr);
273                 switch (shdr.sh_type) {
274                 case SHT_SYMTAB:
275                         symtabscn = scn;
276                         symtabstridx = shdr.sh_link;
277                         break;
278                 case SHT_DYNSYM:
279                         dynsymscn = scn;
280                         dynsymstridx = shdr.sh_link;
281                         break;
282                 default:
283                         break;
284                 }
285         }
286         /*
287          * Iterate over the Dynamic Symbols table to find the symbol.
288          * Then look up the string name in STRTAB (.dynstr)
289          */
290         if ((data = elf_getdata(dynsymscn, NULL)) == NULL) {
291                 DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1));
292                 goto symtab;
293         }
294         i = 0;
295         while (gelf_getsym(data, i++, &sym) != NULL) {
296                 /*
297                  * Calculate the address mapped to the virtual memory
298                  * by rtld.
299                  */
300                 if (ehdr.e_type != ET_EXEC)
301                         rsym = map->pr_vaddr + sym.st_value;
302                 else
303                         rsym = sym.st_value;
304                 if (addr >= rsym && addr < rsym + sym.st_size) {
305                         s = elf_strptr(e, dynsymstridx, sym.st_name);
306                         if (s) {
307                                 demangle(s, name, namesz);
308                                 memcpy(symcopy, &sym, sizeof(sym));
309                                 /*
310                                  * DTrace expects the st_value to contain
311                                  * only the address relative to the start of
312                                  * the function.
313                                  */
314                                 symcopy->st_value = rsym;
315                                 error = 0;
316                                 goto out;
317                         }
318                 }
319         }
320 symtab:
321         /*
322          * Iterate over the Symbols Table to find the symbol.
323          * Then look up the string name in STRTAB (.dynstr)
324          */
325         if ((data = elf_getdata(symtabscn, NULL)) == NULL) {
326                 DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1));
327                 goto err2;
328         }
329         i = 0;
330         while (gelf_getsym(data, i++, &sym) != NULL) {
331                 /*
332                  * Calculate the address mapped to the virtual memory
333                  * by rtld.
334                  */
335                 if (ehdr.e_type != ET_EXEC)
336                         rsym = map->pr_vaddr + sym.st_value;
337                 else
338                         rsym = sym.st_value;
339                 if (addr >= rsym && addr < rsym + sym.st_size) {
340                         s = elf_strptr(e, symtabstridx, sym.st_name);
341                         if (s) {
342                                 demangle(s, name, namesz);
343                                 memcpy(symcopy, &sym, sizeof(sym));
344                                 /*
345                                  * DTrace expects the st_value to contain
346                                  * only the address relative to the start of
347                                  * the function.
348                                  */
349                                 symcopy->st_value = rsym;
350                                 error = 0;
351                                 goto out;
352                         }
353                 }
354         }
355 out:
356 err2:
357         elf_end(e);
358 err1:
359         close(fd);
360 err0:
361         free(map);
362         return (error);
363 }
364
365 prmap_t *
366 proc_name2map(struct proc_handle *p, const char *name)
367 {
368         size_t i;
369         int cnt;
370         prmap_t *map;
371         char tmppath[MAXPATHLEN];
372         struct kinfo_vmentry *kves, *kve;
373         rd_loadobj_t *rdl;
374
375         /*
376          * If we haven't iterated over the list of loaded objects,
377          * librtld_db isn't yet initialized and it's very likely
378          * that librtld_db called us. We need to do the heavy
379          * lifting here to find the symbol librtld_db is looking for.
380          */
381         if (p->nobjs == 0) {
382                 if ((kves = kinfo_getvmmap(proc_getpid(p), &cnt)) == NULL)
383                         return (NULL);
384                 for (i = 0; i < (size_t)cnt; i++) {
385                         kve = kves + i;
386                         basename_r(kve->kve_path, tmppath);
387                         if (strcmp(tmppath, name) == 0) {
388                                 map = proc_addr2map(p, kve->kve_start);
389                                 free(kves);
390                                 return (map);
391                         }
392                 }
393                 free(kves);
394                 return (NULL);
395         }
396         if ((name == NULL || strcmp(name, "a.out") == 0) &&
397             p->rdexec != NULL) {
398                 map = proc_addr2map(p, p->rdexec->rdl_saddr);
399                 return (map);
400         }
401         for (i = 0; i < p->nobjs; i++) {
402                 rdl = &p->rdobjs[i];
403                 basename_r(rdl->rdl_path, tmppath);
404                 if (strcmp(tmppath, name) == 0) {
405                         if ((map = malloc(sizeof(*map))) == NULL)
406                                 return (NULL);
407                         proc_rdl2prmap(rdl, map);
408                         return (map);
409                 }
410         }
411
412         return (NULL);
413 }
414
415 int
416 proc_name2sym(struct proc_handle *p, const char *object, const char *symbol,
417     GElf_Sym *symcopy)
418 {
419         Elf *e;
420         Elf_Scn *scn, *dynsymscn = NULL, *symtabscn = NULL;
421         Elf_Data *data;
422         GElf_Shdr shdr;
423         GElf_Sym sym;
424         GElf_Ehdr ehdr;
425         int fd, error = -1;
426         size_t i;
427         prmap_t *map;
428         char *s;
429         unsigned long symtabstridx = 0, dynsymstridx = 0;
430
431         if ((map = proc_name2map(p, object)) == NULL) {
432                 DPRINTFX("ERROR: couldn't find object %s", object);
433                 goto err0;
434         }
435         if ((fd = open(map->pr_mapname, O_RDONLY, 0)) < 0) {
436                 DPRINTF("ERROR: open %s failed", map->pr_mapname);
437                 goto err0;
438         }
439         if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
440                 DPRINTFX("ERROR: elf_begin() failed: %s", elf_errmsg(-1));
441                 goto err1;
442         }
443         if (gelf_getehdr(e, &ehdr) == NULL) {
444                 DPRINTFX("ERROR: gelf_getehdr() failed: %s", elf_errmsg(-1));
445                 goto err2;
446         }
447         /*
448          * Find the index of the STRTAB and SYMTAB sections to locate
449          * symbol names.
450          */
451         scn = NULL;
452         while ((scn = elf_nextscn(e, scn)) != NULL) {
453                 gelf_getshdr(scn, &shdr);
454                 switch (shdr.sh_type) {
455                 case SHT_SYMTAB:
456                         symtabscn = scn;
457                         symtabstridx = shdr.sh_link;
458                         break;
459                 case SHT_DYNSYM:
460                         dynsymscn = scn;
461                         dynsymstridx = shdr.sh_link;
462                         break;
463                 default:
464                         break;
465                 }
466         }
467         /*
468          * Iterate over the Dynamic Symbols table to find the symbol.
469          * Then look up the string name in STRTAB (.dynstr)
470          */
471         if ((data = elf_getdata(dynsymscn, NULL))) {
472                 i = 0;
473                 while (gelf_getsym(data, i++, &sym) != NULL) {
474                         s = elf_strptr(e, dynsymstridx, sym.st_name);
475                         if (s && strcmp(s, symbol) == 0) {
476                                 memcpy(symcopy, &sym, sizeof(sym));
477                                 if (ehdr.e_type != ET_EXEC)
478                                         symcopy->st_value += map->pr_vaddr;
479                                 error = 0;
480                                 goto out;
481                         }
482                 }
483         }
484         /*
485          * Iterate over the Symbols Table to find the symbol.
486          * Then look up the string name in STRTAB (.dynstr)
487          */
488         if ((data = elf_getdata(symtabscn, NULL))) {
489                 i = 0;
490                 while (gelf_getsym(data, i++, &sym) != NULL) {
491                         s = elf_strptr(e, symtabstridx, sym.st_name);
492                         if (s && strcmp(s, symbol) == 0) {
493                                 memcpy(symcopy, &sym, sizeof(sym));
494                                 if (ehdr.e_type != ET_EXEC)
495                                         symcopy->st_value += map->pr_vaddr;
496                                 error = 0;
497                                 goto out;
498                         }
499                 }
500         }
501 out:
502         DPRINTFX("found addr 0x%lx for %s", symcopy->st_value, symbol);
503 err2:
504         elf_end(e);
505 err1:
506         close(fd);
507 err0:
508         free(map);
509
510         return (error);
511 }
512
513
514 int
515 proc_iter_symbyaddr(struct proc_handle *p, const char *object, int which,
516     int mask, proc_sym_f *func, void *cd)
517 {
518         Elf *e;
519         int i, fd;
520         prmap_t *map;
521         Elf_Scn *scn, *foundscn = NULL;
522         Elf_Data *data;
523         GElf_Ehdr ehdr;
524         GElf_Shdr shdr;
525         GElf_Sym sym;
526         unsigned long stridx = -1;
527         char *s;
528         int error = -1;
529
530         if ((map = proc_name2map(p, object)) == NULL)
531                 return (-1);
532         if ((fd = open(map->pr_mapname, O_RDONLY)) < 0) {
533                 DPRINTF("ERROR: open %s failed", map->pr_mapname);
534                 goto err0;
535         }
536         if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
537                 DPRINTFX("ERROR: elf_begin() failed: %s", elf_errmsg(-1));
538                 goto err1;
539         }
540         if (gelf_getehdr(e, &ehdr) == NULL) {
541                 DPRINTFX("ERROR: gelf_getehdr() failed: %s", elf_errmsg(-1));
542                 goto err2;
543         }
544         /*
545          * Find the section we are looking for.
546          */
547         scn = NULL;
548         while ((scn = elf_nextscn(e, scn)) != NULL) {
549                 gelf_getshdr(scn, &shdr);
550                 if (which == PR_SYMTAB && 
551                     shdr.sh_type == SHT_SYMTAB) {
552                         foundscn = scn;
553                         break;
554                 } else if (which == PR_DYNSYM &&
555                     shdr.sh_type == SHT_DYNSYM) {
556                         foundscn = scn;
557                         break;
558                 }
559         }
560         if (!foundscn)
561                 return (-1);
562         stridx = shdr.sh_link;
563         if ((data = elf_getdata(foundscn, NULL)) == NULL) {
564                 DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1));
565                 goto err2;
566         }
567         i = 0;
568         while (gelf_getsym(data, i++, &sym) != NULL) {
569                 if (GELF_ST_BIND(sym.st_info) == STB_LOCAL &&
570                     (mask & BIND_LOCAL) == 0)
571                         continue;
572                 if (GELF_ST_BIND(sym.st_info) == STB_GLOBAL &&
573                     (mask & BIND_GLOBAL) == 0)
574                         continue;
575                 if (GELF_ST_BIND(sym.st_info) == STB_WEAK &&
576                     (mask & BIND_WEAK) == 0)
577                         continue;
578                 if (GELF_ST_TYPE(sym.st_info) == STT_NOTYPE &&
579                     (mask & TYPE_NOTYPE) == 0)
580                         continue;
581                 if (GELF_ST_TYPE(sym.st_info) == STT_OBJECT &&
582                     (mask & TYPE_OBJECT) == 0)
583                         continue;
584                 if (GELF_ST_TYPE(sym.st_info) == STT_FUNC &&
585                     (mask & TYPE_FUNC) == 0)
586                         continue;
587                 if (GELF_ST_TYPE(sym.st_info) == STT_SECTION &&
588                     (mask & TYPE_SECTION) == 0)
589                         continue;
590                 if (GELF_ST_TYPE(sym.st_info) == STT_FILE &&
591                     (mask & TYPE_FILE) == 0)
592                         continue;
593                 s = elf_strptr(e, stridx, sym.st_name);
594                 if (ehdr.e_type != ET_EXEC)
595                         sym.st_value += map->pr_vaddr;
596                 (*func)(cd, &sym, s);
597         }
598         error = 0;
599 err2:
600         elf_end(e);
601 err1:
602         close(fd);
603 err0:
604         free(map);
605         return (error);
606 }