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