提交 18c0e02e 编写于 作者: R Rich Felker

add dl_iterate_phdr interface

patches by Alex Caudill (npx). the dynamic-linked version is almost
identical to the final submitted patch; I just added a couple missing
lines for saving the phdr address when the dynamic linker is invoked
directly to run a program, and removed a couple to avoid introducing
another unnecessary type. the static-linked version is based on npx's
draft. it could use some improvements which are contingent on the
startup code saving some additional information for later use.
上级 76f28cfc
#ifndef _LINK_H
#define _LINK_H
#include <elf.h>
#define __NEED_size_t
#include <bits/alltypes.h>
#if UINTPTR_MAX > 0xffffffff
#define ElfW(type) Elf64_ ## type
#else
#define ElfW(type) Elf32_ ## type
#endif
struct dl_phdr_info {
ElfW(Addr) dlpi_addr;
const char *dlpi_name;
const ElfW(Phdr) *dlpi_phdr;
ElfW(Half) dlpi_phnum;
unsigned long long int dlpi_adds;
unsigned long long int dlpi_subs;
size_t dlpi_tls_modid;
void *dlpi_tls_data;
};
int dl_iterate_phdr(int (*)(struct dl_phdr_info *, size_t, void *), void *);
#endif
#ifndef SHARED
#include <elf.h>
#include <link.h>
#include "libc.h"
#define AUX_CNT 38
int dl_iterate_phdr(int(*callback)(struct dl_phdr_info *info, size_t size, void *data), void *data)
{
unsigned char *p;
ElfW(Phdr) *phdr, *tls_phdr=0;
size_t base = 0;
size_t n;
struct dl_phdr_info info;
size_t i, aux[AUX_CNT];
for (i=0; libc.auxv[i]; i+=2)
if (libc.auxv[i]<AUX_CNT) aux[libc.auxv[i]] = libc.auxv[i+1];
for (p=(void *)aux[AT_PHDR],n=aux[AT_PHNUM]; n; n--,p+=aux[AT_PHENT]) {
phdr = (void *)p;
if (phdr->p_type == PT_PHDR)
base = aux[AT_PHDR] - phdr->p_vaddr;
if (phdr->p_type == PT_TLS)
tls_phdr = phdr;
}
info.dlpi_addr = base;
info.dlpi_name = "/proc/self/exe";
info.dlpi_phdr = (void *)aux[AT_PHDR];
info.dlpi_phnum = aux[AT_PHNUM];
info.dlpi_adds = 0;
info.dlpi_subs = 0;
if (tls_phdr) {
info.dlpi_tls_modid = 1;
info.dlpi_tls_data = (void *)(base + tls_phdr->p_vaddr);
} else {
info.dlpi_tls_modid = 0;
info.dlpi_tls_data = 0;
}
return (callback)(&info, sizeof (info), data);
}
#endif
......@@ -13,6 +13,7 @@
#include <errno.h>
#include <limits.h>
#include <elf.h>
#include <link.h>
#include <setjmp.h>
#include <pthread.h>
#include <ctype.h>
......@@ -56,6 +57,8 @@ struct dso {
size_t *dynv;
struct dso *next, *prev;
Phdr *phdr;
int phnum;
int refcnt;
Sym *syms;
uint32_t *hashtab;
......@@ -91,6 +94,7 @@ void *__install_initial_tls(void *);
static struct dso *head, *tail, *ldso, *fini_head;
static char *env_path, *sys_path, *r_path;
static unsigned long long gencnt;
static int ssp_used;
static int runtime;
static int ldd_mode;
......@@ -323,6 +327,8 @@ static void *map_library(int fd, struct dso *dso)
eh->e_phoff = sizeof *eh;
}
ph = (void *)((char *)buf + eh->e_phoff);
dso->phdr = ph;
dso->phnum = eh->e_phnum;
for (i=eh->e_phnum; i; i--, ph=(void *)((char *)ph+eh->e_phentsize)) {
if (ph->p_type == PT_DYNAMIC)
dyn = ph->p_vaddr;
......@@ -825,18 +831,19 @@ void *__dynlink(int argc, char **argv)
lib->name = lib->shortname = "libc.so";
lib->global = 1;
ehdr = (void *)lib->base;
find_map_range((void *)(aux[AT_BASE]+ehdr->e_phoff),
ehdr->e_phnum, ehdr->e_phentsize, lib);
lib->dynv = (void *)(lib->base + find_dyn(
(void *)(aux[AT_BASE]+ehdr->e_phoff),
ehdr->e_phnum, ehdr->e_phentsize));
lib->phnum = ehdr->e_phnum;
lib->phdr = (void *)(aux[AT_BASE]+ehdr->e_phoff);
find_map_range(lib->phdr, ehdr->e_phnum, ehdr->e_phentsize, lib);
lib->dynv = (void *)(lib->base + find_dyn(lib->phdr,
ehdr->e_phnum, ehdr->e_phentsize));
decode_dyn(lib);
if (aux[AT_PHDR]) {
size_t interp_off = 0;
size_t tls_image = 0;
/* Find load address of the main program, via AT_PHDR vs PT_PHDR. */
phdr = (void *)aux[AT_PHDR];
app->phdr = phdr = (void *)aux[AT_PHDR];
app->phnum = aux[AT_PHNUM];
for (i=aux[AT_PHNUM]; i; i--, phdr=(void *)((char *)phdr + aux[AT_PHENT])) {
if (phdr->p_type == PT_PHDR)
app->base = (void *)(aux[AT_PHDR] - phdr->p_vaddr);
......@@ -884,6 +891,8 @@ void *__dynlink(int argc, char **argv)
close(fd);
lib->name = ldname;
app->name = argv[0];
app->phnum = ehdr->e_phnum;
app->phdr = (void *)(app->base + ehdr->e_phoff);
aux[AT_ENTRY] = ehdr->e_entry;
}
if (app->tls_size) {
......@@ -907,7 +916,8 @@ void *__dynlink(int argc, char **argv)
/* Attach to vdso, if provided by the kernel */
if (search_vec(auxv, &vdso_base, AT_SYSINFO_EHDR)) {
ehdr = (void *)vdso_base;
phdr = (void *)(vdso_base + ehdr->e_phoff);
vdso->phdr = phdr = (void *)(vdso_base + ehdr->e_phoff);
vdso->phnum = ehdr->e_phnum;
for (i=ehdr->e_phnum; i; i--, phdr=(void *)((char *)phdr + ehdr->e_phentsize)) {
if (phdr->p_type == PT_DYNAMIC)
vdso->dynv = (void *)(vdso_base + phdr->p_offset);
......@@ -1068,6 +1078,7 @@ void *dlopen(const char *file, int mode)
orig_tail = tail;
end:
__release_ptc();
if (p) gencnt++;
pthread_rwlock_unlock(&lock);
if (p) do_init_fini(orig_tail);
pthread_setcancelstate(cs, 0);
......@@ -1192,6 +1203,32 @@ void *__dlsym(void *restrict p, const char *restrict s, void *restrict ra)
pthread_rwlock_unlock(&lock);
return res;
}
int dl_iterate_phdr(int(*callback)(struct dl_phdr_info *info, size_t size, void *data), void *data)
{
struct dso *current;
struct dl_phdr_info info;
int ret = 0;
for(current = head; current;) {
info.dlpi_addr = (uintptr_t)current->base;
info.dlpi_name = current->name;
info.dlpi_phdr = current->phdr;
info.dlpi_phnum = current->phnum;
info.dlpi_adds = gencnt;
info.dlpi_subs = 0;
info.dlpi_tls_modid = current->tls_id;
info.dlpi_tls_data = current->tls_image;
ret = (callback)(&info, sizeof (info), data);
if (ret != 0) break;
pthread_rwlock_rdlock(&lock);
current = current->next;
pthread_rwlock_unlock(&lock);
}
return ret;
}
#else
void *dlopen(const char *file, int mode)
{
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册