libproc: Cache ELF handles for loaded objects.
libproc previously created a new handle for each symbol lookup, which gives rather egregious performance for DTrace's ustack() action. With this change libproc will cache the libelf descriptor upon access, making lookups much faster in the common case.
This commit is contained in:
parent
76c6531c65
commit
07a9c2e65d
@ -32,12 +32,24 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/ptrace.h>
|
||||
|
||||
#include <libelf.h>
|
||||
#include <rtld_db.h>
|
||||
|
||||
#include "libproc.h"
|
||||
|
||||
struct procstat;
|
||||
|
||||
struct file_info {
|
||||
Elf *elf;
|
||||
int fd;
|
||||
u_int refs;
|
||||
};
|
||||
|
||||
struct map_info {
|
||||
prmap_t map;
|
||||
struct file_info *file;
|
||||
};
|
||||
|
||||
struct proc_handle {
|
||||
struct proc_handle_public public; /* Public fields. */
|
||||
int flags; /* Process flags. */
|
||||
@ -45,13 +57,13 @@ struct proc_handle {
|
||||
int wstat; /* Process wait status. */
|
||||
int model; /* Process data model. */
|
||||
rd_agent_t *rdap; /* librtld_db agent */
|
||||
rd_loadobj_t *rdobjs; /* Array of loaded objects. */
|
||||
size_t rdobjsz; /* Array size. */
|
||||
size_t nobjs; /* Num. objects currently loaded. */
|
||||
rd_loadobj_t *rdexec; /* rdobj for program executable. */
|
||||
struct lwpstatus lwps; /* Process status. */
|
||||
struct map_info *mappings; /* File mappings for proc. */
|
||||
size_t maparrsz; /* Map array size. */
|
||||
size_t nmappings; /* Number of mappings. */
|
||||
prmap_t *exec_map; /* Executable text mapping. */
|
||||
lwpstatus_t lwps; /* Process status. */
|
||||
struct procstat *procstat; /* libprocstat handle. */
|
||||
char execpath[MAXPATHLEN]; /* Path to program executable. */
|
||||
char execpath[PATH_MAX]; /* Path to program executable. */
|
||||
};
|
||||
|
||||
#ifdef DEBUG
|
||||
|
@ -131,7 +131,7 @@ char *proc_objname(struct proc_handle *, uintptr_t, char *, size_t);
|
||||
prmap_t *proc_obj2map(struct proc_handle *, const char *);
|
||||
int proc_iter_objs(struct proc_handle *, proc_map_f *, void *);
|
||||
int proc_iter_symbyaddr(struct proc_handle *, const char *, int,
|
||||
int, proc_sym_f *, void *);
|
||||
int, proc_sym_f *, void *);
|
||||
int proc_addr2sym(struct proc_handle *, uintptr_t, char *, size_t, GElf_Sym *);
|
||||
int proc_attach(pid_t pid, int flags, struct proc_handle **pphdl);
|
||||
int proc_continue(struct proc_handle *);
|
||||
|
@ -230,8 +230,24 @@ proc_create(const char *file, char * const *argv, proc_child_func *pcf,
|
||||
void
|
||||
proc_free(struct proc_handle *phdl)
|
||||
{
|
||||
struct file_info *file;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < phdl->nmappings; i++) {
|
||||
file = phdl->mappings[i].file;
|
||||
if (file != NULL && --file->refs == 0) {
|
||||
if (file->elf != NULL) {
|
||||
(void)elf_end(file->elf);
|
||||
(void)close(file->fd);
|
||||
}
|
||||
free(file);
|
||||
}
|
||||
}
|
||||
if (phdl->maparrsz > 0)
|
||||
free(phdl->mappings);
|
||||
if (phdl->procstat != NULL)
|
||||
procstat_close(phdl->procstat);
|
||||
if (phdl->rdap != NULL)
|
||||
rd_delete(phdl->rdap);
|
||||
free(phdl);
|
||||
}
|
||||
|
@ -31,46 +31,99 @@
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <rtld_db.h>
|
||||
|
||||
#include "_libproc.h"
|
||||
|
||||
static void rdl2prmap(const rd_loadobj_t *, prmap_t *);
|
||||
|
||||
static int
|
||||
map_iter(const rd_loadobj_t *lop, void *arg)
|
||||
{
|
||||
struct proc_handle *phdl = arg;
|
||||
struct file_info *file;
|
||||
struct map_info *mapping, *tmp;
|
||||
struct proc_handle *phdl;
|
||||
size_t i;
|
||||
|
||||
if (phdl->nobjs >= phdl->rdobjsz) {
|
||||
phdl->rdobjsz *= 2;
|
||||
phdl->rdobjs = reallocf(phdl->rdobjs, sizeof(*phdl->rdobjs) *
|
||||
phdl->rdobjsz);
|
||||
if (phdl->rdobjs == NULL)
|
||||
phdl = arg;
|
||||
if (phdl->nmappings >= phdl->maparrsz) {
|
||||
phdl->maparrsz *= 2;
|
||||
tmp = reallocarray(phdl->mappings, phdl->maparrsz,
|
||||
sizeof(*phdl->mappings));
|
||||
if (tmp == NULL)
|
||||
return (-1);
|
||||
phdl->mappings = tmp;
|
||||
}
|
||||
|
||||
mapping = &phdl->mappings[phdl->nmappings];
|
||||
rdl2prmap(lop, &mapping->map);
|
||||
if (strcmp(lop->rdl_path, phdl->execpath) == 0 &&
|
||||
(lop->rdl_prot & RD_RDL_X) != 0)
|
||||
phdl->rdexec = &phdl->rdobjs[phdl->nobjs];
|
||||
memcpy(&phdl->rdobjs[phdl->nobjs++], lop, sizeof(*lop));
|
||||
phdl->exec_map = &mapping->map;
|
||||
|
||||
file = NULL;
|
||||
if (lop->rdl_path[0] != '\0') {
|
||||
/* Look for an existing mapping of the same file. */
|
||||
for (i = 0; i < phdl->nmappings; i++)
|
||||
if (strcmp(mapping->map.pr_mapname,
|
||||
phdl->mappings[i].map.pr_mapname) == 0) {
|
||||
file = phdl->mappings[i].file;
|
||||
break;
|
||||
}
|
||||
|
||||
if (file == NULL) {
|
||||
file = malloc(sizeof(*file));
|
||||
if (file == NULL)
|
||||
return (-1);
|
||||
file->elf = NULL;
|
||||
file->fd = -1;
|
||||
file->refs = 1;
|
||||
} else
|
||||
file->refs++;
|
||||
}
|
||||
mapping->file = file;
|
||||
phdl->nmappings++;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
rdl2prmap(const rd_loadobj_t *rdl, prmap_t *map)
|
||||
{
|
||||
|
||||
map->pr_vaddr = rdl->rdl_saddr;
|
||||
map->pr_size = rdl->rdl_eaddr - rdl->rdl_saddr;
|
||||
map->pr_offset = rdl->rdl_offset;
|
||||
map->pr_mflags = 0;
|
||||
if (rdl->rdl_prot & RD_RDL_R)
|
||||
map->pr_mflags |= MA_READ;
|
||||
if (rdl->rdl_prot & RD_RDL_W)
|
||||
map->pr_mflags |= MA_WRITE;
|
||||
if (rdl->rdl_prot & RD_RDL_X)
|
||||
map->pr_mflags |= MA_EXEC;
|
||||
(void)strlcpy(map->pr_mapname, rdl->rdl_path,
|
||||
sizeof(map->pr_mapname));
|
||||
}
|
||||
|
||||
rd_agent_t *
|
||||
proc_rdagent(struct proc_handle *phdl)
|
||||
{
|
||||
|
||||
if (phdl->rdap == NULL && phdl->status != PS_UNDEAD &&
|
||||
phdl->status != PS_IDLE) {
|
||||
if ((phdl->rdap = rd_new(phdl)) != NULL) {
|
||||
phdl->rdobjs = malloc(sizeof(*phdl->rdobjs) * 64);
|
||||
phdl->rdobjsz = 64;
|
||||
if (phdl->rdobjs == NULL)
|
||||
return (phdl->rdap);
|
||||
rd_loadobj_iter(phdl->rdap, map_iter, phdl);
|
||||
}
|
||||
}
|
||||
if ((phdl->rdap = rd_new(phdl)) == NULL)
|
||||
return (NULL);
|
||||
|
||||
phdl->maparrsz = 64;
|
||||
phdl->mappings = calloc(phdl->maparrsz,
|
||||
sizeof(*phdl->mappings));
|
||||
if (phdl->mappings == NULL)
|
||||
return (phdl->rdap);
|
||||
if (rd_loadobj_iter(phdl->rdap, map_iter, phdl) != RD_OK)
|
||||
return (NULL);
|
||||
}
|
||||
return (phdl->rdap);
|
||||
}
|
||||
|
||||
@ -78,7 +131,6 @@ void
|
||||
proc_updatesyms(struct proc_handle *phdl)
|
||||
{
|
||||
|
||||
memset(phdl->rdobjs, 0, sizeof(*phdl->rdobjs) * phdl->rdobjsz);
|
||||
phdl->nobjs = 0;
|
||||
memset(phdl->mappings, 0, sizeof(*phdl->mappings) * phdl->maparrsz);
|
||||
rd_loadobj_iter(phdl->rdap, map_iter, phdl);
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
/*-
|
||||
* Copyright (c) 2016 Mark Johnston <markj@FreeBSD.org>
|
||||
* Copyright (c) 2010 The FreeBSD Foundation
|
||||
* Copyright (c) 2008 John Birrell (jb@freebsd.org)
|
||||
* All rights reserved.
|
||||
@ -64,8 +65,6 @@ typedef struct ctf_file ctf_file_t;
|
||||
extern char *__cxa_demangle(const char *, char *, size_t *, int *);
|
||||
#endif /* NO_CXA_DEMANGLE */
|
||||
|
||||
static void proc_rdl2prmap(rd_loadobj_t *, prmap_t *);
|
||||
|
||||
static int
|
||||
crc32_file(int fd, uint32_t *crc)
|
||||
{
|
||||
@ -131,18 +130,27 @@ open_debug_file(char *path, const char *debugfile, uint32_t crc)
|
||||
* returned.
|
||||
*/
|
||||
static int
|
||||
open_object(prmap_t *map, Elf **elfp, int *fdp)
|
||||
open_object(struct map_info *mapping)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
GElf_Shdr shdr;
|
||||
Elf *e, *e2;
|
||||
Elf_Data *data;
|
||||
Elf_Scn *scn;
|
||||
struct file_info *file;
|
||||
prmap_t *map;
|
||||
const char *debugfile, *scnname;
|
||||
size_t ndx;
|
||||
uint32_t crc;
|
||||
int fd, fd2;
|
||||
|
||||
if (mapping->map.pr_mapname[0] == '\0')
|
||||
return (-1); /* anonymous object */
|
||||
if (mapping->file->elf != NULL)
|
||||
return (0); /* already loaded */
|
||||
|
||||
file = mapping->file;
|
||||
map = &mapping->map;
|
||||
if ((fd = open(map->pr_mapname, O_RDONLY | O_CLOEXEC)) < 0) {
|
||||
DPRINTF("ERROR: open %s failed", map->pr_mapname);
|
||||
return (-1);
|
||||
@ -225,8 +233,8 @@ open_object(prmap_t *map, Elf **elfp, int *fdp)
|
||||
|
||||
internal:
|
||||
/* We didn't find a debug file, just return the object's descriptor. */
|
||||
*elfp = e;
|
||||
*fdp = fd;
|
||||
file->elf = e;
|
||||
file->fd = fd;
|
||||
return (0);
|
||||
|
||||
external:
|
||||
@ -237,8 +245,8 @@ open_object(prmap_t *map, Elf **elfp, int *fdp)
|
||||
}
|
||||
(void)elf_end(e);
|
||||
(void)close(fd);
|
||||
*elfp = e2;
|
||||
*fdp = fd2;
|
||||
file->elf = e2;
|
||||
file->fd = fd2;
|
||||
return (0);
|
||||
|
||||
err:
|
||||
@ -248,164 +256,105 @@ open_object(prmap_t *map, Elf **elfp, int *fdp)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
static void
|
||||
proc_rdl2prmap(rd_loadobj_t *rdl, prmap_t *map)
|
||||
{
|
||||
map->pr_vaddr = rdl->rdl_saddr;
|
||||
map->pr_size = rdl->rdl_eaddr - rdl->rdl_saddr;
|
||||
map->pr_offset = rdl->rdl_offset;
|
||||
map->pr_mflags = 0;
|
||||
if (rdl->rdl_prot & RD_RDL_R)
|
||||
map->pr_mflags |= MA_READ;
|
||||
if (rdl->rdl_prot & RD_RDL_W)
|
||||
map->pr_mflags |= MA_WRITE;
|
||||
if (rdl->rdl_prot & RD_RDL_X)
|
||||
map->pr_mflags |= MA_EXEC;
|
||||
strlcpy(map->pr_mapname, rdl->rdl_path,
|
||||
sizeof(map->pr_mapname));
|
||||
}
|
||||
|
||||
char *
|
||||
proc_objname(struct proc_handle *p, uintptr_t addr, char *objname,
|
||||
size_t objnamesz)
|
||||
{
|
||||
prmap_t *map;
|
||||
size_t i;
|
||||
rd_loadobj_t *rdl;
|
||||
|
||||
for (i = 0; i < p->nobjs; i++) {
|
||||
rdl = &p->rdobjs[i];
|
||||
if (addr >= rdl->rdl_saddr && addr < rdl->rdl_eaddr) {
|
||||
strlcpy(objname, rdl->rdl_path, objnamesz);
|
||||
for (i = 0; i < p->nmappings; i++) {
|
||||
map = &p->mappings[i].map;
|
||||
if (addr >= map->pr_vaddr &&
|
||||
addr < map->pr_vaddr + map->pr_size) {
|
||||
strlcpy(objname, map->pr_mapname, objnamesz);
|
||||
return (objname);
|
||||
}
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Currently just returns the first mapping of the named object, effectively
|
||||
* what Plmid_to_map(p, PR_LMID_EVERY, objname) does in illumos libproc.
|
||||
*/
|
||||
prmap_t *
|
||||
proc_obj2map(struct proc_handle *p, const char *objname)
|
||||
{
|
||||
size_t i;
|
||||
char path[PATH_MAX], *base;
|
||||
prmap_t *map;
|
||||
rd_loadobj_t *rdl;
|
||||
char path[MAXPATHLEN];
|
||||
size_t i;
|
||||
|
||||
rdl = NULL;
|
||||
for (i = 0; i < p->nobjs; i++) {
|
||||
basename_r(p->rdobjs[i].rdl_path, path);
|
||||
if (strcmp(path, objname) == 0) {
|
||||
rdl = &p->rdobjs[i];
|
||||
map = NULL;
|
||||
for (i = 0; i < p->nmappings; i++) {
|
||||
strlcpy(path, p->mappings[i].map.pr_mapname, sizeof(path));
|
||||
base = basename(path);
|
||||
if (strcmp(base, objname) == 0) {
|
||||
map = &p->mappings[i].map;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (rdl == NULL) {
|
||||
if (strcmp(objname, "a.out") == 0 && p->rdexec != NULL)
|
||||
rdl = p->rdexec;
|
||||
else
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if ((map = malloc(sizeof(*map))) == NULL)
|
||||
return (NULL);
|
||||
proc_rdl2prmap(rdl, map);
|
||||
if (map == NULL && strcmp(objname, "a.out") == 0 && p->exec_map != NULL)
|
||||
map = p->exec_map;
|
||||
return (map);
|
||||
}
|
||||
|
||||
int
|
||||
proc_iter_objs(struct proc_handle *p, proc_map_f *func, void *cd)
|
||||
{
|
||||
char last[MAXPATHLEN], path[MAXPATHLEN], *base;
|
||||
prmap_t *map;
|
||||
size_t i;
|
||||
rd_loadobj_t *rdl;
|
||||
prmap_t map;
|
||||
char path[MAXPATHLEN];
|
||||
char last[MAXPATHLEN];
|
||||
int error;
|
||||
|
||||
if (p->nobjs == 0)
|
||||
return (-1);
|
||||
if (p->nmappings == 0)
|
||||
if (proc_rdagent(p) == NULL)
|
||||
return (-1);
|
||||
|
||||
error = 0;
|
||||
memset(last, 0, sizeof(last));
|
||||
for (i = 0; i < p->nobjs; i++) {
|
||||
rdl = &p->rdobjs[i];
|
||||
proc_rdl2prmap(rdl, &map);
|
||||
basename_r(rdl->rdl_path, path);
|
||||
for (i = 0; i < p->nmappings; i++) {
|
||||
map = &p->mappings[i].map;
|
||||
strlcpy(path, map->pr_mapname, sizeof(path));
|
||||
base = basename(path);
|
||||
/*
|
||||
* We shouldn't call the callback twice with the same object.
|
||||
* To do that we are assuming the fact that if there are
|
||||
* repeated object names (i.e. different mappings for the
|
||||
* same object) they occur next to each other.
|
||||
*/
|
||||
if (strcmp(path, last) == 0)
|
||||
if (strcmp(base, last) == 0)
|
||||
continue;
|
||||
if ((error = (*func)(cd, &map, path)) != 0)
|
||||
if ((error = (*func)(cd, map, base)) != 0)
|
||||
break;
|
||||
strlcpy(last, path, sizeof(last));
|
||||
}
|
||||
return (error);
|
||||
}
|
||||
|
||||
static struct map_info *
|
||||
_proc_addr2map(struct proc_handle *p, uintptr_t addr)
|
||||
{
|
||||
struct map_info *mapping;
|
||||
size_t i;
|
||||
|
||||
if (p->nmappings == 0)
|
||||
if (proc_rdagent(p) == NULL)
|
||||
return (NULL);
|
||||
for (i = 0; i < p->nmappings; i++) {
|
||||
mapping = &p->mappings[i];
|
||||
if (addr >= mapping->map.pr_vaddr &&
|
||||
addr < mapping->map.pr_vaddr + mapping->map.pr_size)
|
||||
return (mapping);
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
prmap_t *
|
||||
proc_addr2map(struct proc_handle *p, uintptr_t addr)
|
||||
{
|
||||
size_t i;
|
||||
int cnt, lastvn = 0;
|
||||
prmap_t *map;
|
||||
rd_loadobj_t *rdl;
|
||||
struct kinfo_vmentry *kves, *kve;
|
||||
|
||||
/*
|
||||
* If we don't have a cache of listed objects, we need to query
|
||||
* it ourselves.
|
||||
*/
|
||||
if (p->nobjs == 0) {
|
||||
if ((kves = kinfo_getvmmap(proc_getpid(p), &cnt)) == NULL)
|
||||
return (NULL);
|
||||
for (i = 0; i < (size_t)cnt; i++) {
|
||||
kve = kves + i;
|
||||
if (kve->kve_type == KVME_TYPE_VNODE)
|
||||
lastvn = i;
|
||||
if (addr >= kve->kve_start && addr < kve->kve_end) {
|
||||
if ((map = malloc(sizeof(*map))) == NULL) {
|
||||
free(kves);
|
||||
return (NULL);
|
||||
}
|
||||
map->pr_vaddr = kve->kve_start;
|
||||
map->pr_size = kve->kve_end - kve->kve_start;
|
||||
map->pr_offset = kve->kve_offset;
|
||||
map->pr_mflags = 0;
|
||||
if (kve->kve_protection & KVME_PROT_READ)
|
||||
map->pr_mflags |= MA_READ;
|
||||
if (kve->kve_protection & KVME_PROT_WRITE)
|
||||
map->pr_mflags |= MA_WRITE;
|
||||
if (kve->kve_protection & KVME_PROT_EXEC)
|
||||
map->pr_mflags |= MA_EXEC;
|
||||
if (kve->kve_flags & KVME_FLAG_COW)
|
||||
map->pr_mflags |= MA_COW;
|
||||
if (kve->kve_flags & KVME_FLAG_NEEDS_COPY)
|
||||
map->pr_mflags |= MA_NEEDS_COPY;
|
||||
if (kve->kve_flags & KVME_FLAG_NOCOREDUMP)
|
||||
map->pr_mflags |= MA_NOCOREDUMP;
|
||||
strlcpy(map->pr_mapname, kves[lastvn].kve_path,
|
||||
sizeof(map->pr_mapname));
|
||||
free(kves);
|
||||
return (map);
|
||||
}
|
||||
}
|
||||
free(kves);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
for (i = 0; i < p->nobjs; i++) {
|
||||
rdl = &p->rdobjs[i];
|
||||
if (addr >= rdl->rdl_saddr && addr < rdl->rdl_eaddr) {
|
||||
if ((map = malloc(sizeof(*map))) == NULL)
|
||||
return (NULL);
|
||||
proc_rdl2prmap(rdl, map);
|
||||
return (map);
|
||||
}
|
||||
}
|
||||
return (NULL);
|
||||
return (&_proc_addr2map(p, addr)->map);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -452,21 +401,23 @@ proc_addr2sym(struct proc_handle *p, uintptr_t addr, char *name,
|
||||
GElf_Ehdr ehdr;
|
||||
GElf_Shdr shdr;
|
||||
Elf *e;
|
||||
Elf_Scn *scn, *dynsymscn = NULL, *symtabscn = NULL;
|
||||
prmap_t *map;
|
||||
Elf_Scn *scn, *dynsymscn, *symtabscn;
|
||||
struct map_info *mapping;
|
||||
const char *s;
|
||||
uintptr_t off;
|
||||
u_long symtabstridx = 0, dynsymstridx = 0;
|
||||
int fd, error = -1;
|
||||
u_long symtabstridx, dynsymstridx;
|
||||
int error = -1;
|
||||
|
||||
if ((map = proc_addr2map(p, addr)) == NULL) {
|
||||
if ((mapping = _proc_addr2map(p, addr)) == NULL) {
|
||||
DPRINTFX("ERROR: proc_addr2map failed to resolve 0x%jx", addr);
|
||||
return (-1);
|
||||
}
|
||||
if (open_object(map, &e, &fd) != 0) {
|
||||
DPRINTFX("ERROR: failed to open object %s", map->pr_mapname);
|
||||
if (open_object(mapping) != 0) {
|
||||
DPRINTFX("ERROR: failed to open object %s",
|
||||
mapping->map.pr_mapname);
|
||||
return (-1);
|
||||
}
|
||||
e = mapping->file->elf;
|
||||
if (gelf_getehdr(e, &ehdr) == NULL) {
|
||||
DPRINTFX("ERROR: gelf_getehdr() failed: %s", elf_errmsg(-1));
|
||||
goto err;
|
||||
@ -476,7 +427,8 @@ proc_addr2sym(struct proc_handle *p, uintptr_t addr, char *name,
|
||||
* Find the index of the STRTAB and SYMTAB sections to locate
|
||||
* symbol names.
|
||||
*/
|
||||
scn = NULL;
|
||||
symtabstridx = dynsymstridx = 0;
|
||||
scn = dynsymscn = symtabscn = NULL;
|
||||
while ((scn = elf_nextscn(e, scn)) != NULL) {
|
||||
gelf_getshdr(scn, &shdr);
|
||||
switch (shdr.sh_type) {
|
||||
@ -491,7 +443,7 @@ proc_addr2sym(struct proc_handle *p, uintptr_t addr, char *name,
|
||||
}
|
||||
}
|
||||
|
||||
off = ehdr.e_type == ET_EXEC ? 0 : map->pr_vaddr;
|
||||
off = ehdr.e_type == ET_EXEC ? 0 : mapping->map.pr_vaddr;
|
||||
|
||||
/*
|
||||
* First look up the symbol in the dynsymtab, and fall back to the
|
||||
@ -508,56 +460,39 @@ proc_addr2sym(struct proc_handle *p, uintptr_t addr, char *name,
|
||||
out:
|
||||
demangle(s, name, namesz);
|
||||
err:
|
||||
(void)elf_end(e);
|
||||
(void)close(fd);
|
||||
free(map);
|
||||
return (error);
|
||||
}
|
||||
|
||||
static struct map_info *
|
||||
_proc_name2map(struct proc_handle *p, const char *name)
|
||||
{
|
||||
char path[MAXPATHLEN], *base;
|
||||
struct map_info *mapping;
|
||||
size_t i;
|
||||
|
||||
mapping = NULL;
|
||||
if (p->nmappings == 0)
|
||||
if (proc_rdagent(p) == NULL)
|
||||
return (NULL);
|
||||
for (i = 0; i < p->nmappings; i++) {
|
||||
mapping = &p->mappings[i];
|
||||
(void)strlcpy(path, mapping->map.pr_mapname, sizeof(path));
|
||||
base = basename(path);
|
||||
if (strcmp(base, name) == 0)
|
||||
break;
|
||||
}
|
||||
if (i == p->nmappings)
|
||||
mapping = NULL;
|
||||
if (mapping == NULL && strcmp(name, "a.out") == 0)
|
||||
mapping = _proc_addr2map(p, p->exec_map->pr_vaddr);
|
||||
return (mapping);
|
||||
}
|
||||
|
||||
prmap_t *
|
||||
proc_name2map(struct proc_handle *p, const char *name)
|
||||
{
|
||||
size_t i;
|
||||
int cnt;
|
||||
prmap_t *map = NULL;
|
||||
char tmppath[MAXPATHLEN];
|
||||
struct kinfo_vmentry *kves, *kve;
|
||||
rd_loadobj_t *rdl;
|
||||
|
||||
/*
|
||||
* If we haven't iterated over the list of loaded objects,
|
||||
* librtld_db isn't yet initialized and it's very likely
|
||||
* that librtld_db called us. We need to do the heavy
|
||||
* lifting here to find the symbol librtld_db is looking for.
|
||||
*/
|
||||
if (p->nobjs == 0) {
|
||||
if ((kves = kinfo_getvmmap(proc_getpid(p), &cnt)) == NULL)
|
||||
return (NULL);
|
||||
for (i = 0; i < (size_t)cnt; i++) {
|
||||
kve = kves + i;
|
||||
basename_r(kve->kve_path, tmppath);
|
||||
if (strcmp(tmppath, name) == 0) {
|
||||
map = proc_addr2map(p, kve->kve_start);
|
||||
break;
|
||||
}
|
||||
}
|
||||
free(kves);
|
||||
} else
|
||||
for (i = 0; i < p->nobjs; i++) {
|
||||
rdl = &p->rdobjs[i];
|
||||
basename_r(rdl->rdl_path, tmppath);
|
||||
if (strcmp(tmppath, name) == 0) {
|
||||
if ((map = malloc(sizeof(*map))) == NULL)
|
||||
return (NULL);
|
||||
proc_rdl2prmap(rdl, map);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (map == NULL && strcmp(name, "a.out") == 0 && p->rdexec != NULL)
|
||||
map = proc_addr2map(p, p->rdexec->rdl_saddr);
|
||||
|
||||
return (map);
|
||||
return (&_proc_name2map(p, name)->map);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -592,23 +527,25 @@ int
|
||||
proc_name2sym(struct proc_handle *p, const char *object, const char *symbol,
|
||||
GElf_Sym *symcopy, prsyminfo_t *si)
|
||||
{
|
||||
Elf *e;
|
||||
Elf_Scn *scn, *dynsymscn = NULL, *symtabscn = NULL;
|
||||
GElf_Shdr shdr;
|
||||
GElf_Ehdr ehdr;
|
||||
prmap_t *map;
|
||||
GElf_Shdr shdr;
|
||||
Elf *e;
|
||||
Elf_Scn *scn, *dynsymscn, *symtabscn;
|
||||
struct map_info *mapping;
|
||||
uintptr_t off;
|
||||
u_long symtabstridx = 0, dynsymstridx = 0;
|
||||
int fd, error = -1;
|
||||
u_long symtabstridx, dynsymstridx;
|
||||
int error = -1;
|
||||
|
||||
if ((map = proc_name2map(p, object)) == NULL) {
|
||||
if ((mapping = _proc_name2map(p, object)) == NULL) {
|
||||
DPRINTFX("ERROR: proc_name2map failed to resolve %s", object);
|
||||
return (-1);
|
||||
}
|
||||
if (open_object(map, &e, &fd) != 0) {
|
||||
DPRINTFX("ERROR: failed to open object %s", map->pr_mapname);
|
||||
if (open_object(mapping) != 0) {
|
||||
DPRINTFX("ERROR: failed to open object %s",
|
||||
mapping->map.pr_mapname);
|
||||
return (-1);
|
||||
}
|
||||
e = mapping->file->elf;
|
||||
if (gelf_getehdr(e, &ehdr) == NULL) {
|
||||
DPRINTFX("ERROR: gelf_getehdr() failed: %s", elf_errmsg(-1));
|
||||
goto err;
|
||||
@ -618,7 +555,8 @@ proc_name2sym(struct proc_handle *p, const char *object, const char *symbol,
|
||||
* Find the index of the STRTAB and SYMTAB sections to locate
|
||||
* symbol names.
|
||||
*/
|
||||
scn = NULL;
|
||||
symtabstridx = dynsymstridx = 0;
|
||||
scn = dynsymscn = symtabscn = NULL;
|
||||
while ((scn = elf_nextscn(e, scn)) != NULL) {
|
||||
gelf_getshdr(scn, &shdr);
|
||||
switch (shdr.sh_type) {
|
||||
@ -646,13 +584,10 @@ proc_name2sym(struct proc_handle *p, const char *object, const char *symbol,
|
||||
goto out;
|
||||
|
||||
out:
|
||||
off = ehdr.e_type == ET_EXEC ? 0 : map->pr_vaddr;
|
||||
off = ehdr.e_type == ET_EXEC ? 0 : mapping->map.pr_vaddr;
|
||||
symcopy->st_value += off;
|
||||
|
||||
err:
|
||||
(void)elf_end(e);
|
||||
(void)close(fd);
|
||||
free(map);
|
||||
return (error);
|
||||
}
|
||||
|
||||
@ -668,7 +603,6 @@ proc_name2ctf(struct proc_handle *p, const char *name)
|
||||
return (NULL);
|
||||
|
||||
ctf = ctf_open(map->pr_mapname, &error);
|
||||
free(map);
|
||||
return (ctf);
|
||||
#else
|
||||
(void)p;
|
||||
@ -681,26 +615,27 @@ int
|
||||
proc_iter_symbyaddr(struct proc_handle *p, const char *object, int which,
|
||||
int mask, proc_sym_f *func, void *cd)
|
||||
{
|
||||
Elf *e;
|
||||
int i, fd;
|
||||
prmap_t *map;
|
||||
Elf_Scn *scn, *foundscn;
|
||||
Elf_Data *data;
|
||||
GElf_Ehdr ehdr;
|
||||
GElf_Shdr shdr;
|
||||
GElf_Sym sym;
|
||||
unsigned long stridx = -1;
|
||||
Elf *e;
|
||||
Elf_Scn *scn, *foundscn;
|
||||
Elf_Data *data;
|
||||
struct map_info *mapping;
|
||||
char *s;
|
||||
int error = -1;
|
||||
unsigned long stridx = -1;
|
||||
int error = -1, i;
|
||||
|
||||
if ((map = proc_name2map(p, object)) == NULL) {
|
||||
if ((mapping = _proc_name2map(p, object)) == NULL) {
|
||||
DPRINTFX("ERROR: proc_name2map failed to resolve %s", object);
|
||||
return (-1);
|
||||
}
|
||||
if (open_object(map, &e, &fd) != 0) {
|
||||
DPRINTFX("ERROR: failed to open object %s", map->pr_mapname);
|
||||
if (open_object(mapping) != 0) {
|
||||
DPRINTFX("ERROR: failed to open object %s",
|
||||
mapping->map.pr_mapname);
|
||||
return (-1);
|
||||
}
|
||||
e = mapping->file->elf;
|
||||
if (gelf_getehdr(e, &ehdr) == NULL) {
|
||||
DPRINTFX("ERROR: gelf_getehdr() failed: %s", elf_errmsg(-1));
|
||||
goto err;
|
||||
@ -755,14 +690,11 @@ proc_iter_symbyaddr(struct proc_handle *p, const char *object, int which,
|
||||
continue;
|
||||
s = elf_strptr(e, stridx, sym.st_name);
|
||||
if (ehdr.e_type != ET_EXEC)
|
||||
sym.st_value += map->pr_vaddr;
|
||||
sym.st_value += mapping->map.pr_vaddr;
|
||||
if ((error = (*func)(cd, &sym, s)) != 0)
|
||||
goto err;
|
||||
}
|
||||
error = 0;
|
||||
err:
|
||||
elf_end(e);
|
||||
close(fd);
|
||||
free(map);
|
||||
return (error);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user