Implement dl_iterate_phdr function.
Convert boolean flags in internal Obj_Entry structure into bitfields. Properly check for loaded segment alignment in map_object.
This commit is contained in:
parent
fb6395da91
commit
49f90ad282
@ -61,7 +61,6 @@ map_object(int fd, const char *path, const struct stat *sb)
|
|||||||
Elf_Phdr **segs;
|
Elf_Phdr **segs;
|
||||||
int nsegs;
|
int nsegs;
|
||||||
Elf_Phdr *phdyn;
|
Elf_Phdr *phdyn;
|
||||||
Elf_Phdr *phphdr;
|
|
||||||
Elf_Phdr *phinterp;
|
Elf_Phdr *phinterp;
|
||||||
Elf_Phdr *phtls;
|
Elf_Phdr *phtls;
|
||||||
caddr_t mapbase;
|
caddr_t mapbase;
|
||||||
@ -79,7 +78,8 @@ map_object(int fd, const char *path, const struct stat *sb)
|
|||||||
Elf_Addr clear_vaddr;
|
Elf_Addr clear_vaddr;
|
||||||
caddr_t clear_addr;
|
caddr_t clear_addr;
|
||||||
caddr_t clear_page;
|
caddr_t clear_page;
|
||||||
size_t nclear;
|
Elf_Addr phdr_vaddr;
|
||||||
|
size_t nclear, phsize;
|
||||||
Elf_Addr bss_vaddr;
|
Elf_Addr bss_vaddr;
|
||||||
Elf_Addr bss_vlimit;
|
Elf_Addr bss_vlimit;
|
||||||
caddr_t bss_addr;
|
caddr_t bss_addr;
|
||||||
@ -95,9 +95,11 @@ map_object(int fd, const char *path, const struct stat *sb)
|
|||||||
* in that order.
|
* in that order.
|
||||||
*/
|
*/
|
||||||
phdr = (Elf_Phdr *) ((char *)hdr + hdr->e_phoff);
|
phdr = (Elf_Phdr *) ((char *)hdr + hdr->e_phoff);
|
||||||
|
phsize = hdr->e_phnum * sizeof (phdr[0]);
|
||||||
phlimit = phdr + hdr->e_phnum;
|
phlimit = phdr + hdr->e_phnum;
|
||||||
nsegs = -1;
|
nsegs = -1;
|
||||||
phdyn = phphdr = phinterp = phtls = NULL;
|
phdyn = phinterp = phtls = NULL;
|
||||||
|
phdr_vaddr = 0;
|
||||||
segs = alloca(sizeof(segs[0]) * hdr->e_phnum);
|
segs = alloca(sizeof(segs[0]) * hdr->e_phnum);
|
||||||
while (phdr < phlimit) {
|
while (phdr < phlimit) {
|
||||||
switch (phdr->p_type) {
|
switch (phdr->p_type) {
|
||||||
@ -108,7 +110,7 @@ map_object(int fd, const char *path, const struct stat *sb)
|
|||||||
|
|
||||||
case PT_LOAD:
|
case PT_LOAD:
|
||||||
segs[++nsegs] = phdr;
|
segs[++nsegs] = phdr;
|
||||||
if (segs[nsegs]->p_align < PAGE_SIZE) {
|
if ((segs[nsegs]->p_align & (PAGE_SIZE - 1)) != 0) {
|
||||||
_rtld_error("%s: PT_LOAD segment %d not page-aligned",
|
_rtld_error("%s: PT_LOAD segment %d not page-aligned",
|
||||||
path, nsegs);
|
path, nsegs);
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -116,7 +118,8 @@ map_object(int fd, const char *path, const struct stat *sb)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case PT_PHDR:
|
case PT_PHDR:
|
||||||
phphdr = phdr;
|
phdr_vaddr = phdr->p_vaddr;
|
||||||
|
phsize = phdr->p_memsz;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PT_DYNAMIC:
|
case PT_DYNAMIC:
|
||||||
@ -211,6 +214,11 @@ map_object(int fd, const char *path, const struct stat *sb)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (phdr_vaddr == 0 && data_offset <= hdr->e_phoff &&
|
||||||
|
(data_vlimit - data_vaddr + data_offset) >=
|
||||||
|
(hdr->e_phoff + hdr->e_phnum * sizeof (Elf_Phdr))) {
|
||||||
|
phdr_vaddr = data_vaddr + hdr->e_phoff - data_offset;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
obj = obj_new();
|
obj = obj_new();
|
||||||
@ -227,10 +235,19 @@ map_object(int fd, const char *path, const struct stat *sb)
|
|||||||
obj->dynamic = (const Elf_Dyn *) (obj->relocbase + phdyn->p_vaddr);
|
obj->dynamic = (const Elf_Dyn *) (obj->relocbase + phdyn->p_vaddr);
|
||||||
if (hdr->e_entry != 0)
|
if (hdr->e_entry != 0)
|
||||||
obj->entry = (caddr_t) (obj->relocbase + hdr->e_entry);
|
obj->entry = (caddr_t) (obj->relocbase + hdr->e_entry);
|
||||||
if (phphdr != NULL) {
|
if (phdr_vaddr != 0) {
|
||||||
obj->phdr = (const Elf_Phdr *) (obj->relocbase + phphdr->p_vaddr);
|
obj->phdr = (const Elf_Phdr *) (obj->relocbase + phdr_vaddr);
|
||||||
obj->phsize = phphdr->p_memsz;
|
} else {
|
||||||
|
obj->phdr = malloc(phsize);
|
||||||
|
if (obj->phdr == NULL) {
|
||||||
|
obj_free(obj);
|
||||||
|
_rtld_error("%s: cannot allocate program header", path);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
memcpy((char *)obj->phdr, (char *)hdr + hdr->e_phoff, phsize);
|
||||||
|
obj->phdr_alloc = true;
|
||||||
}
|
}
|
||||||
|
obj->phsize = phsize;
|
||||||
if (phinterp != NULL)
|
if (phinterp != NULL)
|
||||||
obj->interp = (const char *) (obj->relocbase + phinterp->p_vaddr);
|
obj->interp = (const char *) (obj->relocbase + phinterp->p_vaddr);
|
||||||
if (phtls != NULL) {
|
if (phtls != NULL) {
|
||||||
@ -307,7 +324,6 @@ obj_free(Obj_Entry *obj)
|
|||||||
|
|
||||||
if (obj->tls_done)
|
if (obj->tls_done)
|
||||||
free_tls_offset(obj);
|
free_tls_offset(obj);
|
||||||
free(obj->path);
|
|
||||||
while (obj->needed != NULL) {
|
while (obj->needed != NULL) {
|
||||||
Needed_Entry *needed = obj->needed;
|
Needed_Entry *needed = obj->needed;
|
||||||
obj->needed = needed->next;
|
obj->needed = needed->next;
|
||||||
@ -328,9 +344,16 @@ obj_free(Obj_Entry *obj)
|
|||||||
STAILQ_REMOVE_HEAD(&obj->dagmembers, link);
|
STAILQ_REMOVE_HEAD(&obj->dagmembers, link);
|
||||||
free(elm);
|
free(elm);
|
||||||
}
|
}
|
||||||
free(obj->vertab);
|
if (obj->vertab)
|
||||||
free(obj->origin_path);
|
free(obj->vertab);
|
||||||
free(obj->priv);
|
if (obj->origin_path)
|
||||||
|
free(obj->origin_path);
|
||||||
|
if (obj->priv)
|
||||||
|
free(obj->priv);
|
||||||
|
if (obj->path)
|
||||||
|
free(obj->path);
|
||||||
|
if (obj->phdr_alloc)
|
||||||
|
free((void *)obj->phdr);
|
||||||
free(obj);
|
free(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,6 +164,7 @@ static Obj_Entry **obj_tail; /* Link field of last object in list */
|
|||||||
static Obj_Entry *obj_main; /* The main program shared object */
|
static Obj_Entry *obj_main; /* The main program shared object */
|
||||||
static Obj_Entry obj_rtld; /* The dynamic linker shared object */
|
static Obj_Entry obj_rtld; /* The dynamic linker shared object */
|
||||||
static unsigned int obj_count; /* Number of objects in obj_list */
|
static unsigned int obj_count; /* Number of objects in obj_list */
|
||||||
|
static unsigned int obj_loads; /* Number of objects in obj_list */
|
||||||
|
|
||||||
static Objlist list_global = /* Objects dlopened with RTLD_GLOBAL */
|
static Objlist list_global = /* Objects dlopened with RTLD_GLOBAL */
|
||||||
STAILQ_HEAD_INITIALIZER(list_global);
|
STAILQ_HEAD_INITIALIZER(list_global);
|
||||||
@ -204,6 +205,7 @@ static func_ptr_type exports[] = {
|
|||||||
(func_ptr_type) &__tls_get_addr,
|
(func_ptr_type) &__tls_get_addr,
|
||||||
(func_ptr_type) &_rtld_allocate_tls,
|
(func_ptr_type) &_rtld_allocate_tls,
|
||||||
(func_ptr_type) &_rtld_free_tls,
|
(func_ptr_type) &_rtld_free_tls,
|
||||||
|
(func_ptr_type) &dl_iterate_phdr,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -423,6 +425,7 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
|
|||||||
*obj_tail = obj_main;
|
*obj_tail = obj_main;
|
||||||
obj_tail = &obj_main->next;
|
obj_tail = &obj_main->next;
|
||||||
obj_count++;
|
obj_count++;
|
||||||
|
obj_loads++;
|
||||||
/* Make sure we don't call the main program's init and fini functions. */
|
/* Make sure we don't call the main program's init and fini functions. */
|
||||||
obj_main->init = obj_main->fini = (Elf_Addr)NULL;
|
obj_main->init = obj_main->fini = (Elf_Addr)NULL;
|
||||||
|
|
||||||
@ -1387,6 +1390,7 @@ do_load_object(int fd, const char *name, char *path, struct stat *sbp)
|
|||||||
*obj_tail = obj;
|
*obj_tail = obj;
|
||||||
obj_tail = &obj->next;
|
obj_tail = &obj->next;
|
||||||
obj_count++;
|
obj_count++;
|
||||||
|
obj_loads++;
|
||||||
linkmap_add(obj); /* for GDB & dlinfo() */
|
linkmap_add(obj); /* for GDB & dlinfo() */
|
||||||
|
|
||||||
dbg(" %p .. %p: %s", obj->mapbase,
|
dbg(" %p .. %p: %s", obj->mapbase,
|
||||||
@ -2079,6 +2083,37 @@ dlinfo(void *handle, int request, void *p)
|
|||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
dl_iterate_phdr(__dl_iterate_hdr_callback callback, void *param)
|
||||||
|
{
|
||||||
|
struct dl_phdr_info phdr_info;
|
||||||
|
const Obj_Entry *obj;
|
||||||
|
int error, lockstate;
|
||||||
|
|
||||||
|
lockstate = rlock_acquire(rtld_bind_lock);
|
||||||
|
|
||||||
|
error = 0;
|
||||||
|
|
||||||
|
for (obj = obj_list; obj != NULL; obj = obj->next) {
|
||||||
|
phdr_info.dlpi_addr = (Elf_Addr)obj->relocbase;
|
||||||
|
phdr_info.dlpi_name = STAILQ_FIRST(&obj->names) ?
|
||||||
|
STAILQ_FIRST(&obj->names)->name : obj->path;
|
||||||
|
phdr_info.dlpi_phdr = obj->phdr;
|
||||||
|
phdr_info.dlpi_phnum = obj->phsize / sizeof(obj->phdr[0]);
|
||||||
|
phdr_info.dlpi_tls_modid = obj->tlsindex;
|
||||||
|
phdr_info.dlpi_tls_data = obj->tlsinit;
|
||||||
|
phdr_info.dlpi_adds = obj_loads;
|
||||||
|
phdr_info.dlpi_subs = obj_loads - obj_count;
|
||||||
|
|
||||||
|
if ((error = callback(&phdr_info, sizeof phdr_info, param)) != 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
rlock_release(rtld_bind_lock, lockstate);
|
||||||
|
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
|
||||||
struct fill_search_info_args {
|
struct fill_search_info_args {
|
||||||
int request;
|
int request;
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
|
@ -201,15 +201,16 @@ typedef struct Struct_Obj_Entry {
|
|||||||
Elf_Addr init; /* Initialization function to call */
|
Elf_Addr init; /* Initialization function to call */
|
||||||
Elf_Addr fini; /* Termination function to call */
|
Elf_Addr fini; /* Termination function to call */
|
||||||
|
|
||||||
bool mainprog; /* True if this is the main program */
|
bool mainprog : 1; /* True if this is the main program */
|
||||||
bool rtld; /* True if this is the dynamic linker */
|
bool rtld : 1; /* True if this is the dynamic linker */
|
||||||
bool textrel; /* True if there are relocations to text seg */
|
bool textrel : 1; /* True if there are relocations to text seg */
|
||||||
bool symbolic; /* True if generated with "-Bsymbolic" */
|
bool symbolic : 1; /* True if generated with "-Bsymbolic" */
|
||||||
bool bind_now; /* True if all relocations should be made first */
|
bool bind_now : 1; /* True if all relocations should be made first */
|
||||||
bool traced; /* Already printed in ldd trace output */
|
bool traced : 1; /* Already printed in ldd trace output */
|
||||||
bool jmpslots_done; /* Already have relocated the jump slots */
|
bool jmpslots_done : 1; /* Already have relocated the jump slots */
|
||||||
bool init_done; /* Already have added object to init list */
|
bool init_done : 1; /* Already have added object to init list */
|
||||||
bool tls_done; /* Already allocated offset for static TLS */
|
bool tls_done : 1; /* Already allocated offset for static TLS */
|
||||||
|
bool phdr_alloc : 1; /* Phdr is allocated and needs to be freed. */
|
||||||
|
|
||||||
struct link_map linkmap; /* for GDB and dlinfo() */
|
struct link_map linkmap; /* for GDB and dlinfo() */
|
||||||
Objlist dldags; /* Object belongs to these dlopened DAGs (%) */
|
Objlist dldags; /* Object belongs to these dlopened DAGs (%) */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user