10266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes/*
20266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes * Copyright (C) 2006 The Android Open Source Project
30266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes * All rights reserved.
40266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes *
50266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes * Redistribution and use in source and binary forms, with or without
60266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes * modification, are permitted provided that the following conditions
70266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes * are met:
80266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes *  * Redistributions of source code must retain the above copyright
90266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes *    notice, this list of conditions and the following disclaimer.
100266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes *  * Redistributions in binary form must reproduce the above copyright
110266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes *    notice, this list of conditions and the following disclaimer in
120266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes *    the documentation and/or other materials provided with the
130266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes *    distribution.
140266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes *
150266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
160266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
170266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
180266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
190266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
200266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
210266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
220266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
230266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
240266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
250266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
260266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes * SUCH DAMAGE.
270266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes */
280266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes
290266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes#include <elf.h>
303002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes#include <string.h>
310266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes#include <sys/auxv.h>
320266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes#include <sys/types.h>
330266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes#include <link.h>
340266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes
350266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes/* ld provides this to us in the default link script */
360266ae5f884d72da58f33a072e865ba131234a5eElliott Hughesextern "C" void* __executable_start;
370266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes
380266ae5f884d72da58f33a072e865ba131234a5eElliott Hughesint dl_iterate_phdr(int (*cb)(struct dl_phdr_info* info, size_t size, void* data), void* data) {
390266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  ElfW(Ehdr)* ehdr = reinterpret_cast<ElfW(Ehdr)*>(&__executable_start);
400266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes
413002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes  if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0) {
423002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes    return -1;
433002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes  }
440266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes
450266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  // Dynamic binaries get their dl_iterate_phdr from the dynamic linker, but
460266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  // static binaries get this. We don't have a list of shared objects to
470266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  // iterate over, since there's really only a single monolithic blob of
480266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  // code/data, plus optionally a VDSO.
490266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes
500266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  struct dl_phdr_info exe_info;
510266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  exe_info.dlpi_addr = 0;
520266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  exe_info.dlpi_name = NULL;
530266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  exe_info.dlpi_phdr = reinterpret_cast<ElfW(Phdr)*>(reinterpret_cast<uintptr_t>(ehdr) + ehdr->e_phoff);
540266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  exe_info.dlpi_phnum = ehdr->e_phnum;
550266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes
563002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes#if defined(AT_SYSINFO_EHDR)
570266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  // Try the executable first.
580266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  int rc = cb(&exe_info, sizeof(exe_info), data);
590266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  if (rc != 0) {
600266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes    return rc;
610266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  }
620266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes
630266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  // Try the VDSO if that didn't work.
640266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  ElfW(Ehdr)* ehdr_vdso = reinterpret_cast<ElfW(Ehdr)*>(getauxval(AT_SYSINFO_EHDR));
650266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  struct dl_phdr_info vdso_info;
660266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  vdso_info.dlpi_addr = 0;
670266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  vdso_info.dlpi_name = NULL;
680266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  vdso_info.dlpi_phdr = reinterpret_cast<ElfW(Phdr)*>(reinterpret_cast<char*>(ehdr_vdso) + ehdr_vdso->e_phoff);
690266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  vdso_info.dlpi_phnum = ehdr_vdso->e_phnum;
700266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  for (size_t i = 0; i < vdso_info.dlpi_phnum; ++i) {
710266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes    if (vdso_info.dlpi_phdr[i].p_type == PT_LOAD) {
720266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes      vdso_info.dlpi_addr = (ElfW(Addr)) ehdr_vdso - vdso_info.dlpi_phdr[i].p_vaddr;
730266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes      break;
740266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes    }
750266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  }
760266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  return cb(&vdso_info, sizeof(vdso_info), data);
770266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes#else
780266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  // There's only the executable to try.
790266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  return cb(&exe_info, sizeof(exe_info), data);
800266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes#endif
810266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes}
82