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