Index: head/lib/libproc/_libproc.h =================================================================== --- head/lib/libproc/_libproc.h (revision 309593) +++ head/lib/libproc/_libproc.h (revision 309594) @@ -1,65 +1,77 @@ /*- * Copyright (c) 2008 John Birrell (jb@freebsd.org) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef __LIBPROC_H_ #define __LIBPROC_H_ #include #include +#include #include #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. */ int status; /* Process status (PS_*). */ 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 #define DPRINTF(...) warn(__VA_ARGS__) #define DPRINTFX(...) warnx(__VA_ARGS__) #else #define DPRINTF(...) do { } while (0) #define DPRINTFX(...) do { } while (0) #endif #endif /* __LIBPROC_H_ */ Index: head/lib/libproc/libproc.h =================================================================== --- head/lib/libproc/libproc.h (revision 309593) +++ head/lib/libproc/libproc.h (revision 309594) @@ -1,166 +1,166 @@ /*- * Copyright (c) 2010 The FreeBSD Foundation * Copyright (c) 2008 John Birrell (jb@freebsd.org) * All rights reserved. * * Portions of this software were developed by Rui Paulo under sponsorship * from the FreeBSD Foundation. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _LIBPROC_H_ #define _LIBPROC_H_ #include #include #include struct ctf_file; struct proc_handle; typedef void (*proc_child_func)(void *); /* Values returned by proc_state(). */ #define PS_IDLE 1 #define PS_STOP 2 #define PS_RUN 3 #define PS_UNDEAD 4 #define PS_DEAD 5 #define PS_LOST 6 /* Reason values for proc_detach(). */ #define PRELEASE_HANG 1 #define PRELEASE_KILL 2 typedef struct prmap { uintptr_t pr_vaddr; /* Virtual address. */ size_t pr_size; /* Mapping size in bytes */ size_t pr_offset; /* Mapping offset in object */ char pr_mapname[PATH_MAX]; /* Mapping filename */ uint8_t pr_mflags; /* Protection flags */ #define MA_READ 0x01 #define MA_WRITE 0x02 #define MA_EXEC 0x04 #define MA_COW 0x08 #define MA_NEEDS_COPY 0x10 #define MA_NOCOREDUMP 0x20 } prmap_t; typedef struct prsyminfo { u_int prs_lmid; /* Map id. */ u_int prs_id; /* Symbol id. */ } prsyminfo_t; typedef int proc_map_f(void *, const prmap_t *, const char *); typedef int proc_sym_f(void *, const GElf_Sym *, const char *); /* Values for ELF sections */ #define PR_SYMTAB 1 #define PR_DYNSYM 2 /* Values for the 'mask' parameter in the iteration functions */ #define BIND_LOCAL 0x0001 #define BIND_GLOBAL 0x0002 #define BIND_WEAK 0x0004 #define BIND_ANY (BIND_LOCAL|BIND_GLOBAL|BIND_WEAK) #define TYPE_NOTYPE 0x0100 #define TYPE_OBJECT 0x0200 #define TYPE_FUNC 0x0400 #define TYPE_SECTION 0x0800 #define TYPE_FILE 0x1000 #define TYPE_ANY (TYPE_NOTYPE|TYPE_OBJECT|TYPE_FUNC|TYPE_SECTION|\ TYPE_FILE) typedef enum { REG_PC, REG_SP, REG_RVAL1, REG_RVAL2 } proc_reg_t; #define SIG2STR_MAX 8 typedef struct lwpstatus { int pr_why; #define PR_REQUESTED 1 #define PR_FAULTED 2 #define PR_SYSENTRY 3 #define PR_SYSEXIT 4 #define PR_SIGNALLED 5 int pr_what; #define FLTBPT -1 } lwpstatus_t; #define PR_MODEL_ILP32 1 #define PR_MODEL_LP64 2 struct proc_handle_public { pid_t pid; }; #define proc_getpid(phdl) (((struct proc_handle_public *)(phdl))->pid) /* Function prototype definitions. */ __BEGIN_DECLS prmap_t *proc_addr2map(struct proc_handle *, uintptr_t); prmap_t *proc_name2map(struct proc_handle *, const char *); 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 *); int proc_clearflags(struct proc_handle *, int); int proc_create(const char *, char * const *, proc_child_func *, void *, struct proc_handle **); int proc_detach(struct proc_handle *, int); int proc_getflags(struct proc_handle *); int proc_name2sym(struct proc_handle *, const char *, const char *, GElf_Sym *, prsyminfo_t *); struct ctf_file *proc_name2ctf(struct proc_handle *, const char *); int proc_setflags(struct proc_handle *, int); int proc_state(struct proc_handle *); int proc_getmodel(struct proc_handle *); int proc_wstatus(struct proc_handle *); int proc_getwstat(struct proc_handle *); char * proc_signame(int, char *, size_t); int proc_read(struct proc_handle *, void *, size_t, size_t); const lwpstatus_t *proc_getlwpstatus(struct proc_handle *); void proc_free(struct proc_handle *); rd_agent_t *proc_rdagent(struct proc_handle *); void proc_updatesyms(struct proc_handle *); int proc_bkptset(struct proc_handle *, uintptr_t, unsigned long *); int proc_bkptdel(struct proc_handle *, uintptr_t, unsigned long); void proc_bkptregadj(unsigned long *); int proc_bkptexec(struct proc_handle *, unsigned long); int proc_regget(struct proc_handle *, proc_reg_t, unsigned long *); int proc_regset(struct proc_handle *, proc_reg_t, unsigned long); __END_DECLS #endif /* _LIBPROC_H_ */ Index: head/lib/libproc/proc_create.c =================================================================== --- head/lib/libproc/proc_create.c (revision 309593) +++ head/lib/libproc/proc_create.c (revision 309594) @@ -1,237 +1,253 @@ /*- * Copyright (c) 2008 John Birrell (jb@freebsd.org) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include "_libproc.h" static int getelfclass(int); static int proc_init(pid_t, int, int, struct proc_handle **); static int getelfclass(int fd) { GElf_Ehdr ehdr; Elf *e; int class; class = ELFCLASSNONE; if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) goto out; if (gelf_getehdr(e, &ehdr) == NULL) goto out; class = ehdr.e_ident[EI_CLASS]; out: (void)elf_end(e); return (class); } static int proc_init(pid_t pid, int flags, int status, struct proc_handle **pphdl) { struct kinfo_proc *kp; struct proc_handle *phdl; int error, class, count, fd; error = ENOMEM; if ((phdl = malloc(sizeof(*phdl))) == NULL) goto out; memset(phdl, 0, sizeof(*phdl)); phdl->public.pid = pid; phdl->flags = flags; phdl->status = status; phdl->procstat = procstat_open_sysctl(); if (phdl->procstat == NULL) goto out; /* Obtain a path to the executable. */ if ((kp = procstat_getprocs(phdl->procstat, KERN_PROC_PID, pid, &count)) == NULL) goto out; error = procstat_getpathname(phdl->procstat, kp, phdl->execpath, sizeof(phdl->execpath)); procstat_freeprocs(phdl->procstat, kp); if (error != 0) goto out; /* Use it to determine the data model for the process. */ if ((fd = open(phdl->execpath, O_RDONLY)) < 0) { error = errno; goto out; } class = getelfclass(fd); switch (class) { case ELFCLASS64: phdl->model = PR_MODEL_LP64; break; case ELFCLASS32: phdl->model = PR_MODEL_ILP32; break; case ELFCLASSNONE: default: error = EINVAL; break; } (void)close(fd); out: *pphdl = phdl; return (error); } int proc_attach(pid_t pid, int flags, struct proc_handle **pphdl) { struct proc_handle *phdl; int error, status; if (pid == 0 || pid == getpid()) return (EINVAL); if (elf_version(EV_CURRENT) == EV_NONE) return (ENOENT); /* * Allocate memory for the process handle, a structure containing * all things related to the process. */ error = proc_init(pid, flags, PS_RUN, &phdl); if (error != 0) goto out; if (ptrace(PT_ATTACH, proc_getpid(phdl), 0, 0) != 0) { error = errno; DPRINTF("ERROR: cannot ptrace child process %d", pid); goto out; } /* Wait for the child process to stop. */ if (waitpid(pid, &status, WUNTRACED) == -1) { error = errno; DPRINTF("ERROR: child process %d didn't stop as expected", pid); goto out; } /* Check for an unexpected status. */ if (!WIFSTOPPED(status)) DPRINTFX("ERROR: child process %d status 0x%x", pid, status); else phdl->status = PS_STOP; out: if (error && phdl != NULL) { proc_free(phdl); phdl = NULL; } *pphdl = phdl; return (error); } int proc_create(const char *file, char * const *argv, proc_child_func *pcf, void *child_arg, struct proc_handle **pphdl) { struct proc_handle *phdl; int error = 0; int status; pid_t pid; if (elf_version(EV_CURRENT) == EV_NONE) return (ENOENT); /* Fork a new process. */ if ((pid = vfork()) == -1) error = errno; else if (pid == 0) { /* The child expects to be traced. */ if (ptrace(PT_TRACE_ME, 0, 0, 0) != 0) _exit(1); if (pcf != NULL) (*pcf)(child_arg); /* Execute the specified file: */ execvp(file, argv); /* Couldn't execute the file. */ _exit(2); /* NOTREACHED */ } else { /* The parent owns the process handle. */ error = proc_init(pid, 0, PS_IDLE, &phdl); if (error != 0) goto bad; /* Wait for the child process to stop. */ if (waitpid(pid, &status, WUNTRACED) == -1) { error = errno; DPRINTF("ERROR: child process %d didn't stop as expected", pid); goto bad; } /* Check for an unexpected status. */ if (!WIFSTOPPED(status)) { error = errno; DPRINTFX("ERROR: child process %d status 0x%x", pid, status); goto bad; } else phdl->status = PS_STOP; } bad: if (error && phdl != NULL) { proc_free(phdl); phdl = NULL; } *pphdl = phdl; return (error); } 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); } Index: head/lib/libproc/proc_rtld.c =================================================================== --- head/lib/libproc/proc_rtld.c (revision 309593) +++ head/lib/libproc/proc_rtld.c (revision 309594) @@ -1,84 +1,136 @@ /*- * Copyright (c) 2010 The FreeBSD Foundation * All rights reserved. * * This software was developed by Rui Paulo under sponsorship from the * FreeBSD Foundation. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include -#include #include +#include + #include #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); } 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); } Index: head/lib/libproc/proc_sym.c =================================================================== --- head/lib/libproc/proc_sym.c (revision 309593) +++ head/lib/libproc/proc_sym.c (revision 309594) @@ -1,768 +1,700 @@ /*- + * Copyright (c) 2016 Mark Johnston * Copyright (c) 2010 The FreeBSD Foundation * Copyright (c) 2008 John Birrell (jb@freebsd.org) * All rights reserved. * * Portions of this software were developed by Rui Paulo under sponsorship * from the FreeBSD Foundation. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #ifndef NO_CTF #include #include #endif #include #include #include #include #include #include #include #include #include #ifndef NO_CTF #include #endif #include #include "crc32.h" #include "_libproc.h" #define PATH_DEBUG_DIR "/usr/lib/debug" #ifdef NO_CTF typedef struct ctf_file ctf_file_t; #endif #ifndef NO_CXA_DEMANGLE 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) { uint8_t buf[PAGE_SIZE], *p; size_t n; *crc = ~0; while ((n = read(fd, buf, sizeof(buf))) > 0) { p = &buf[0]; while (n-- > 0) *crc = crc32_tab[(*crc ^ *p++) & 0xff] ^ (*crc >> 8); } *crc = ~*crc; return (n); } static void demangle(const char *symbol, char *buf, size_t len) { #ifndef NO_CXA_DEMANGLE char *dembuf; if (symbol[0] == '_' && symbol[1] == 'Z' && symbol[2]) { dembuf = __cxa_demangle(symbol, NULL, NULL, NULL); if (!dembuf) goto fail; strlcpy(buf, dembuf, len); free(dembuf); return; } fail: #endif /* NO_CXA_DEMANGLE */ strlcpy(buf, symbol, len); } static int open_debug_file(char *path, const char *debugfile, uint32_t crc) { size_t n; uint32_t compcrc; int fd; fd = -1; if ((n = strlcat(path, "/", PATH_MAX)) >= PATH_MAX) return (fd); if (strlcat(path, debugfile, PATH_MAX) >= PATH_MAX) goto out; if ((fd = open(path, O_RDONLY | O_CLOEXEC)) < 0) goto out; if (crc32_file(fd, &compcrc) != 0 || crc != compcrc) { DPRINTFX("ERROR: CRC32 mismatch for %s", path); (void)close(fd); fd = -1; } out: path[n] = '\0'; return (fd); } /* * Obtain an ELF descriptor for the specified mapped object. If a GNU debuglink * section is present, a descriptor for the corresponding debug file is * 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); } if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { DPRINTFX("ERROR: elf_begin() failed: %s", elf_errmsg(-1)); goto err; } scn = NULL; while ((scn = elf_nextscn(e, scn)) != NULL) { if (gelf_getshdr(scn, &shdr) != &shdr) { DPRINTFX("ERROR: gelf_getshdr failed: %s", elf_errmsg(-1)); goto err; } if (shdr.sh_type != SHT_PROGBITS) continue; if (elf_getshdrstrndx(e, &ndx) != 0) { DPRINTFX("ERROR: elf_getshdrstrndx failed: %s", elf_errmsg(-1)); goto err; } if ((scnname = elf_strptr(e, ndx, shdr.sh_name)) == NULL) continue; if (strcmp(scnname, ".gnu_debuglink") == 0) break; } if (scn == NULL) goto internal; if ((data = elf_getdata(scn, NULL)) == NULL) { DPRINTFX("ERROR: elf_getdata failed: %s", elf_errmsg(-1)); goto err; } /* * The data contains a null-terminated file name followed by a 4-byte * CRC. */ if (data->d_size < sizeof(crc) + 1) { DPRINTFX("ERROR: debuglink section is too small (%zd bytes)", data->d_size); goto internal; } if (strnlen(data->d_buf, data->d_size) >= data->d_size - sizeof(crc)) { DPRINTFX("ERROR: no null-terminator in gnu_debuglink section"); goto internal; } debugfile = data->d_buf; memcpy(&crc, (char *)data->d_buf + data->d_size - sizeof(crc), sizeof(crc)); /* * Search for the debug file using the algorithm described in the gdb * documentation: * - look in the directory containing the object, * - look in the subdirectory ".debug" of the directory containing the * object, * - look in the global debug directories (currently /usr/lib/debug). */ (void)strlcpy(path, map->pr_mapname, sizeof(path)); (void)dirname(path); if ((fd2 = open_debug_file(path, debugfile, crc)) >= 0) goto external; if (strlcat(path, "/.debug", sizeof(path)) < sizeof(path) && (fd2 = open_debug_file(path, debugfile, crc)) >= 0) goto external; (void)snprintf(path, sizeof(path), PATH_DEBUG_DIR); if (strlcat(path, map->pr_mapname, sizeof(path)) < sizeof(path)) { (void)dirname(path); if ((fd2 = open_debug_file(path, debugfile, crc)) >= 0) goto external; } 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: if ((e2 = elf_begin(fd2, ELF_C_READ, NULL)) == NULL) { DPRINTFX("ERROR: elf_begin failed: %s", elf_errmsg(-1)); (void)close(fd2); goto err; } (void)elf_end(e); (void)close(fd); - *elfp = e2; - *fdp = fd2; + file->elf = e2; + file->fd = fd2; return (0); err: if (e != NULL) (void)elf_end(e); (void)close(fd); 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); } -prmap_t * -proc_addr2map(struct proc_handle *p, uintptr_t addr) +static struct map_info * +_proc_addr2map(struct proc_handle *p, uintptr_t addr) { + struct map_info *mapping; 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) + if (p->nmappings == 0) + if (proc_rdagent(p) == 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->nmappings; i++) { + mapping = &p->mappings[i]; + if (addr >= mapping->map.pr_vaddr && + addr < mapping->map.pr_vaddr + mapping->map.pr_size) + return (mapping); } - - 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); } +prmap_t * +proc_addr2map(struct proc_handle *p, uintptr_t addr) +{ + + return (&_proc_addr2map(p, addr)->map); +} + /* * Look up the symbol at addr, returning a copy of the symbol and its name. */ static int lookup_addr(Elf *e, Elf_Scn *scn, u_long stridx, uintptr_t off, uintptr_t addr, const char **name, GElf_Sym *symcopy) { GElf_Sym sym; Elf_Data *data; const char *s; uint64_t rsym; int i; if ((data = elf_getdata(scn, NULL)) == NULL) { DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1)); return (1); } for (i = 0; gelf_getsym(data, i, &sym) != NULL; i++) { rsym = off + sym.st_value; if (addr >= rsym && addr < rsym + sym.st_size) { s = elf_strptr(e, stridx, sym.st_name); if (s != NULL) { *name = s; memcpy(symcopy, &sym, sizeof(*symcopy)); /* * DTrace expects the st_value to contain * only the address relative to the start of * the function. */ symcopy->st_value = rsym; return (0); } } } return (1); } int proc_addr2sym(struct proc_handle *p, uintptr_t addr, char *name, size_t namesz, GElf_Sym *symcopy) { 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; } /* * 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) { case SHT_SYMTAB: symtabscn = scn; symtabstridx = shdr.sh_link; break; case SHT_DYNSYM: dynsymscn = scn; dynsymstridx = shdr.sh_link; break; } } - 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 * symtab if the lookup fails. */ error = lookup_addr(e, dynsymscn, dynsymstridx, off, addr, &s, symcopy); if (error == 0) goto out; error = lookup_addr(e, symtabscn, symtabstridx, off, addr, &s, symcopy); if (error != 0) goto err; out: demangle(s, name, namesz); err: - (void)elf_end(e); - (void)close(fd); - free(map); return (error); } -prmap_t * -proc_name2map(struct proc_handle *p, const char *name) +static struct map_info * +_proc_name2map(struct proc_handle *p, const char *name) { + char path[MAXPATHLEN], *base; + struct map_info *mapping; 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) + mapping = NULL; + if (p->nmappings == 0) + if (proc_rdagent(p) == 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; - } - } + 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); +} - if (map == NULL && strcmp(name, "a.out") == 0 && p->rdexec != NULL) - map = proc_addr2map(p, p->rdexec->rdl_saddr); +prmap_t * +proc_name2map(struct proc_handle *p, const char *name) +{ - return (map); + return (&_proc_name2map(p, name)->map); } /* * Look up the symbol with the given name and return a copy of it. */ static int lookup_name(Elf *e, Elf_Scn *scn, u_long stridx, const char *symbol, GElf_Sym *symcopy, prsyminfo_t *si) { GElf_Sym sym; Elf_Data *data; char *s; int i; if ((data = elf_getdata(scn, NULL)) == NULL) { DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1)); return (1); } for (i = 0; gelf_getsym(data, i, &sym) != NULL; i++) { s = elf_strptr(e, stridx, sym.st_name); if (s != NULL && strcmp(s, symbol) == 0) { memcpy(symcopy, &sym, sizeof(*symcopy)); if (si != NULL) si->prs_id = i; return (0); } } return (1); } 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; } /* * 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) { case SHT_SYMTAB: symtabscn = scn; symtabstridx = shdr.sh_link; break; case SHT_DYNSYM: dynsymscn = scn; dynsymstridx = shdr.sh_link; break; } } /* * First look up the symbol in the dynsymtab, and fall back to the * symtab if the lookup fails. */ error = lookup_name(e, dynsymscn, dynsymstridx, symbol, symcopy, si); if (error == 0) goto out; error = lookup_name(e, symtabscn, symtabstridx, symbol, symcopy, si); if (error == 0) 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); } ctf_file_t * proc_name2ctf(struct proc_handle *p, const char *name) { #ifndef NO_CTF ctf_file_t *ctf; prmap_t *map; int error; if ((map = proc_name2map(p, name)) == NULL) return (NULL); ctf = ctf_open(map->pr_mapname, &error); - free(map); return (ctf); #else (void)p; (void)name; return (NULL); #endif } 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; } /* * Find the section we are looking for. */ foundscn = scn = NULL; while ((scn = elf_nextscn(e, scn)) != NULL) { gelf_getshdr(scn, &shdr); if (which == PR_SYMTAB && shdr.sh_type == SHT_SYMTAB) { foundscn = scn; break; } else if (which == PR_DYNSYM && shdr.sh_type == SHT_DYNSYM) { foundscn = scn; break; } } if (!foundscn) return (-1); stridx = shdr.sh_link; if ((data = elf_getdata(foundscn, NULL)) == NULL) { DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1)); goto err; } for (i = 0; gelf_getsym(data, i, &sym) != NULL; i++) { if (GELF_ST_BIND(sym.st_info) == STB_LOCAL && (mask & BIND_LOCAL) == 0) continue; if (GELF_ST_BIND(sym.st_info) == STB_GLOBAL && (mask & BIND_GLOBAL) == 0) continue; if (GELF_ST_BIND(sym.st_info) == STB_WEAK && (mask & BIND_WEAK) == 0) continue; if (GELF_ST_TYPE(sym.st_info) == STT_NOTYPE && (mask & TYPE_NOTYPE) == 0) continue; if (GELF_ST_TYPE(sym.st_info) == STT_OBJECT && (mask & TYPE_OBJECT) == 0) continue; if (GELF_ST_TYPE(sym.st_info) == STT_FUNC && (mask & TYPE_FUNC) == 0) continue; if (GELF_ST_TYPE(sym.st_info) == STT_SECTION && (mask & TYPE_SECTION) == 0) continue; if (GELF_ST_TYPE(sym.st_info) == STT_FILE && (mask & TYPE_FILE) == 0) 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); }