#if defined(__ANDROID__) && __ANDROID_API__ < 21
#include <dlfcn.h>
#include <link.h>
#include "libunwind_i.h"
#include "os-linux.h"
#ifndef IS_ELF
#define IS_ELF(ehdr) ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \
(ehdr).e_ident[EI_MAG1] == ELFMAG1 && \
(ehdr).e_ident[EI_MAG2] == ELFMAG2 && \
(ehdr).e_ident[EI_MAG3] == ELFMAG3)
#endif
HIDDEN int
dl_iterate_phdr (unw_iterate_phdr_callback_t callback,
void *data)
{
static int initialized = 0;
static unw_iterate_phdr_func_t libc_impl;
int rc = 0;
struct map_iterator mi;
unsigned long start, end, offset, flags;
if (!initialized)
{
libc_impl = dlsym (RTLD_NEXT, "dl_iterate_phdr");
initialized = 1;
}
if (libc_impl != NULL)
return libc_impl (callback, data);
if (maps_init (&mi, getpid()) < 0)
return -1;
while (maps_next (&mi, &start, &end, &offset, &flags))
{
Elf_W(Ehdr) *ehdr = (Elf_W(Ehdr) *) start;
Dl_info canonical_info;
if (mi.path[0] != '\0' && (flags & PROT_READ) != 0 && IS_ELF (*ehdr)
&& dladdr (ehdr, &canonical_info) != 0
&& ehdr == canonical_info.dli_fbase)
{
struct dl_phdr_info info;
Elf_W(Phdr) *phdr = (Elf_W(Phdr) *) (start + ehdr->e_phoff);
info.dlpi_addr = start;
info.dlpi_name = canonical_info.dli_fname;
info.dlpi_phdr = phdr;
info.dlpi_phnum = ehdr->e_phnum;
rc = callback (&info, sizeof (info), data);
}
}
maps_close (&mi);
return rc;
}
#endif