Deleted Added
full compact
proc_sym.c (179185) proc_sym.c (210688)
1/*-
1/*-
2 * Copyright (c) 2010 The FreeBSD Foundation
2 * Copyright (c) 2008 John Birrell (jb@freebsd.org)
3 * All rights reserved.
4 *
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 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.

--- 5 unchanged lines hidden (view full) ---

18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
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.

--- 5 unchanged lines hidden (view full) ---

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