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