From: Alex Caudill <alex.caudill@gmail.com>
To: musl@lists.openwall.com
Subject: Re: PATCH: dl_iterate_phdr()
Date: Fri, 12 Oct 2012 08:28:59 -0500 [thread overview]
Message-ID: <CAFXnQt7GKFTBdaNWiX1-2kDxdeyjAQYhLkxJJaMPmL3oLyYoSA@mail.gmail.com> (raw)
In-Reply-To: <20121012000034.GC254@brightrain.aerifal.cx>
[-- Attachment #1: Type: text/plain, Size: 3097 bytes --]
Thanks for the review! To clarify, I meant that the patch is public
domain. This version implements most of your changes and attempts
support for dlopen()'d libraries and vdso.
Some questions:
1.) I guarded link.h with _GNU_SOURCE or _BSD_SOURCE; I'm unclear on
whether this is necessary since it isn't a standard header, so please
let me know your preference.
2.) I'm unsure of how to replace ElfW(Phdr) in dl_phdr_info - or did
you mean that musl should internally use some opaque type for
dl_phdr_info? Also, should ElfW() go in elf.h?
3.) The attached dltest.c reveals a problem with dlopen()'d libraries
which seems to be related to the locking strategy (see output below).
If I don't take the lock and check for current == saved_tail, it
"fixes" the example. At the least, I think this reveals a flaw with
dlopen("foo", RTLD_NOW) - shouldn't it hold the lock until the dso
list has been updated?
This function is used by libunwind and (I think) libgcc_eh for C++
exception support, and it's possible that additional fields in
dl_phdr_info will be necessary in order for those to work unmodified
with musl. I'll look into this today and come up with more tests.
Solaris and FreeBSD, at least, have these appended to struct
dl_phdr_info:
unsigned long long int dlpi_adds; /* total # of loads */
unsigned long long int dlpi_subs; /* total # of unloads */
The dl_iterate_phdr() callback is passed a size arg, and the callback
is responsible for checking the size to ensure that the additional
fields are present. Don't shoot the messenger! :)
TEST OUTPUT:
musl:
name=./dltest (6 segments)
header 0: address= 0x8048034
header 1: address= 0x80480f4
header 2: address= 0x8048000
header 3: address= 0x8049538
header 4: address= 0x804954c
header 5: address= 0
name=/lib/ld-musl-i386.so.1 (4 segments)
header 0: address=0x28049000
header 1: address=0x280c7714
header 2: address=0x280c77d8
header 3: address=0x28049000
FreeBSD libc:
name=/usr/home/alex/dltest (8 segments)
header 0: address= 0x8048034
header 1: address= 0x8048134
header 2: address= 0x8048000
header 3: address= 0x80497d0
header 4: address= 0x80497e4
header 5: address= 0x804814c
header 6: address= 0x8048784
header 7: address= 0x0
name=libc.so.7 (6 segments)
header 0: address=0x2806b000
header 1: address=0x28195000
header 2: address=0x281976b4
header 3: address=0x28195000
header 4: address=0x28194b38
header 5: address=0x2806b000
name=/compat/linux/lib/libavl.so (4 segments)
header 0: address=0x281c3000
header 1: address=0x281c5738
header 2: address=0x281c5738
header 3: address=0x281c3000
[-- Attachment #2: dynlink.patch --]
[-- Type: application/octet-stream, Size: 3447 bytes --]
diff --git a/src/ldso/dynlink.c b/src/ldso/dynlink.c
index c3cb611..503ed0e 100644
--- a/src/ldso/dynlink.c
+++ b/src/ldso/dynlink.c
@@ -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>
@@ -57,6 +58,8 @@ struct dso {
size_t *dynv;
struct dso *next, *prev;
+ Phdr *phdr;
+ uint16_t phnum;
int refcnt;
Sym *syms;
uint32_t *hashtab;
@@ -324,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 = (uint16_t)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;
@@ -815,19 +820,20 @@ 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 = (uint16_t)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];
- for (i=aux[AT_PHNUM]; i; i--, phdr=(void *)((char *)phdr + aux[AT_PHENT])) {
+ app->phdr = phdr = (void *)aux[AT_PHDR];
+ app->phnum = aux[AT_PHNUM];
+ for (i=app->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);
else if (phdr->p_type == PT_INTERP)
@@ -890,7 +896,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);
@@ -1166,6 +1173,30 @@ 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, *saved_tail;
+ struct dl_phdr_info info;
+ int ret = 0;
+
+ pthread_rwlock_rdlock(&lock);
+ saved_tail = tail;
+ pthread_rwlock_unlock(&lock);
+
+ for(current = head; ; current = current->next) {
+ info.dlpi_addr = (uintptr_t)current->base;
+ info.dlpi_name = current->name;
+ info.dlpi_phdr = current->phdr;
+ info.dlpi_phnum = current->phnum;
+
+ ret = (callback)(&info, sizeof (info), data);
+ if (ret != 0) break;
+
+ if (current == saved_tail) break;
+ }
+ return ret;
+}
#else
void *dlopen(const char *file, int mode)
{
[-- Attachment #3: link.h --]
[-- Type: text/x-chdr, Size: 474 bytes --]
#ifndef _LINK_H
#define _LLINK_H
#include <elf.h>
#define __NEED_size_t
#include <bits/alltypes.h>
#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
#ifdef _LP64
#define ElfW(type) Elf64_ ## type
#else
#define ElfW(type) Elf32_ ## type
#endif
struct dl_phdr_info {
uintptr_t dlpi_addr;
const char *dlpi_name;
const ElfW(Phdr) *dlpi_phdr;
uint16_t dlpi_phnum;
};
int dl_iterate_phdr(int (*)(struct dl_phdr_info *, size_t, void *), void *);
#endif
#endif
[-- Attachment #4: dltest.c --]
[-- Type: text/x-csrc, Size: 623 bytes --]
#define _GNU_SOURCE
#include <dlfcn.h>
#include <link.h>
#include <stdlib.h>
#include <stdio.h>
static int
callback(struct dl_phdr_info *info, size_t size, void *data)
{
int j;
printf("name=%s (%d segments)\n", info->dlpi_name,
info->dlpi_phnum);
for (j = 0; j < info->dlpi_phnum; j++)
printf("\t\t header %2d: address=%10p\n", j,
(void *) (info->dlpi_addr + info->dlpi_phdr[j].p_vaddr));
return 0;
}
int
main(int argc, char *argv[])
{
void *test;
test = dlopen("/compat/linux/lib/libavl.so", RTLD_NOW);
dl_iterate_phdr(callback, NULL);
exit(EXIT_SUCCESS);
}
next prev parent reply other threads:[~2012-10-12 13:28 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-10-11 14:29 Alex Caudill
2012-10-11 23:42 ` Rich Felker
2012-10-12 0:00 ` Rich Felker
2012-10-12 13:28 ` Alex Caudill [this message]
2012-10-12 15:43 ` Rich Felker
2012-10-13 1:04 ` Alex Caudill
2012-10-13 1:24 ` Alex Caudill
2012-10-13 1:31 ` Rich Felker
2012-10-15 3:30 ` Rich Felker
2012-10-15 4:47 ` Alex Caudill
2012-10-15 12:41 ` Rich Felker
2012-10-18 20:45 ` Rich Felker
2012-10-31 18:35 ` Alex Caudill
2012-11-01 1:33 ` Rich Felker
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=CAFXnQt7GKFTBdaNWiX1-2kDxdeyjAQYhLkxJJaMPmL3oLyYoSA@mail.gmail.com \
--to=alex.caudill@gmail.com \
--cc=musl@lists.openwall.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://git.vuxu.org/mirror/musl/
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).