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