mirror of git://git.musl-libc.org/musl
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.
This commit is contained in:
parent
76f28cfce5
commit
18c0e02e2b
|
@ -0,0 +1,27 @@
|
|||
#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
|
|
@ -0,0 +1,43 @@
|
|||
#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)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue