linker.cpp revision bc3a5c26f1b9cf29da6abfc3e197258ef4c03362
11dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/*
21dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
31dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * All rights reserved.
41dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
51dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Redistribution and use in source and binary forms, with or without
61dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * modification, are permitted provided that the following conditions
71dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * are met:
81dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *  * Redistributions of source code must retain the above copyright
91dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *    notice, this list of conditions and the following disclaimer.
101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *  * Redistributions in binary form must reproduce the above copyright
111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *    notice, this list of conditions and the following disclaimer in
121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *    the documentation and/or other materials provided with the
131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *    distribution.
141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * SUCH DAMAGE.
271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <linux/auxvec.h>
301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <stdio.h>
321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <stdlib.h>
331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <string.h>
341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <unistd.h>
351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <fcntl.h>
361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <errno.h>
371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <dlfcn.h>
381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <sys/stat.h>
391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
405e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev#include <pthread.h>
411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <sys/mman.h>
431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <sys/atomics.h>
451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* special private C library header - see Android.mk */
471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <bionic_tls.h>
481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include "linker.h"
501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include "linker_debug.h"
511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include "ba.h"
531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
54ba52b3092f361580a5dea7ab8fbe2a227b55ee43James Dong#define SO_MAX 96
551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
56bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley/* Assume average path length of 64 and max 8 paths */
57bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley#define LDPATH_BUFSIZE 512
58bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley#define LDPATH_MAX 8
59bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley
601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* >>> IMPORTANT NOTE - READ ME BEFORE MODIFYING <<<
611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Do NOT use malloc() and friends or pthread_*() code here.
631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Don't use printf() either; it's caused mysterious memory
641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * corruption in the past.
651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * The linker runs before we bring up libc and it's easiest
661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * to make sure it does not depend on any complex libc features
671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * open issues / todo:
691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * - should we do anything special for STB_WEAK symbols?
711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * - are we doing everything we should for ARM_COPY relocations?
721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * - cleaner error reporting
731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * - after linking, set as much stuff as possible to READONLY
741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *   and NOEXEC
751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * - linker hardcodes PAGE_SIZE and PAGE_MASK because the kernel
761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *   headers provide versions that are negative...
771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * - allocate space for soinfo structs dynamically instead of
781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *   having a hard limit (64)
791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * features to add someday:
811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * - dlopen() and friends
831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project*/
851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic int link_image(soinfo *si, unsigned wr_offset);
881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic int socount = 0;
901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic soinfo sopool[SO_MAX];
911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic soinfo *freelist = NULL;
921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic soinfo *solist = &libdl_info;
931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic soinfo *sonext = &libdl_info;
941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
95bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartleystatic char ldpaths_buf[LDPATH_BUFSIZE];
96bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartleystatic const char *ldpaths[LDPATH_MAX + 1];
97bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley
981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint debug_verbosity;
991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic int pid;
1001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if STATS
1021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstruct _link_stats linker_stats;
1031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
1041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if COUNT_PAGES
1061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectunsigned bitmask[4096];
1071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
1081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#ifndef PT_ARM_EXIDX
1101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define PT_ARM_EXIDX    0x70000001      /* .ARM.exidx segment */
1111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
1121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1132e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin#define HOODLUM(name, ret, ...)                                               \
1142e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin    ret name __VA_ARGS__                                                      \
1152e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin    {                                                                         \
1162e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin        char errstr[] = "ERROR: " #name " called from the dynamic linker!\n"; \
1172e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin        write(2, errstr, sizeof(errstr));                                     \
1182e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin        abort();                                                              \
1192e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin    }
1202e85579c34047c305caf15fb0ebe02bf3d001d0eDima ZavinHOODLUM(malloc, void *, (size_t size));
1212e85579c34047c305caf15fb0ebe02bf3d001d0eDima ZavinHOODLUM(free, void, (void *ptr));
1222e85579c34047c305caf15fb0ebe02bf3d001d0eDima ZavinHOODLUM(realloc, void *, (void *ptr, size_t size));
1232e85579c34047c305caf15fb0ebe02bf3d001d0eDima ZavinHOODLUM(calloc, void *, (size_t cnt, size_t size));
1242e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin
1250353195f344666256dba474a15c9ba22cf0cccc9Dima Zavinstatic char tmp_err_buf[768];
1262e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavinstatic char __linker_dl_err_buf[768];
1272e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin#define DL_ERR(fmt, x...)                                                     \
1282e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin    do {                                                                      \
1292e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin        snprintf(__linker_dl_err_buf, sizeof(__linker_dl_err_buf),            \
1302e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin                 "%s[%d]: " fmt, __func__, __LINE__, ##x);                    \
1312e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin        ERROR(fmt, ##x);                                                      \
1322e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin    } while(0)
1332e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin
1342e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavinconst char *linker_get_error(void)
1352e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin{
1362e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin    return (const char *)&__linker_dl_err_buf[0];
1372e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin}
1382e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin
1391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/*
1401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * This function is an empty stub where GDB locates a breakpoint to get notified
1411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * about linker activity.
1421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
1431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectextern void __attribute__((noinline)) rtld_db_dlactivity(void);
1441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic struct r_debug _r_debug = {1, NULL, &rtld_db_dlactivity,
1461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                                  RT_CONSISTENT, 0};
1471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic struct link_map *r_debug_tail = 0;
1481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1495e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchevstatic pthread_mutex_t _r_debug_lock = PTHREAD_MUTEX_INITIALIZER;
1501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic void insert_soinfo_into_debug_map(soinfo * info)
1521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
1531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    struct link_map * map;
1541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* Copy the necessary fields into the debug structure.
1561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     */
1571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    map = &(info->linkmap);
1581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    map->l_addr = info->base;
1591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    map->l_name = (char*) info->name;
1601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* Stick the new library at the end of the list.
1621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * gdb tends to care more about libc than it does
1631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * about leaf libraries, and ordering it this way
1641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * reduces the back-and-forth over the wire.
1651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     */
1661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (r_debug_tail) {
1671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        r_debug_tail->l_next = map;
1681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        map->l_prev = r_debug_tail;
1691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        map->l_next = 0;
1701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    } else {
1711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        _r_debug.r_map = map;
1721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        map->l_prev = 0;
1731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        map->l_next = 0;
1741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
1751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    r_debug_tail = map;
1761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
1771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1785e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchevstatic void remove_soinfo_from_debug_map(soinfo * info)
1795e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev{
1805e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev    struct link_map * map = &(info->linkmap);
1815e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
1825e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev    if (r_debug_tail == map)
1835e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev        r_debug_tail = map->l_prev;
1845e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
1855e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev    if (map->l_prev) map->l_prev->l_next = map->l_next;
1865e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev    if (map->l_next) map->l_next->l_prev = map->l_prev;
1875e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev}
1885e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
1891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectvoid notify_gdb_of_load(soinfo * info)
1901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
1911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (info->flags & FLAG_EXE) {
1921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        // GDB already knows about the main executable
1931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return;
1941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
1951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1965e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev    pthread_mutex_lock(&_r_debug_lock);
1971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    _r_debug.r_state = RT_ADD;
1991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    rtld_db_dlactivity();
2001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    insert_soinfo_into_debug_map(info);
2021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    _r_debug.r_state = RT_CONSISTENT;
2041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    rtld_db_dlactivity();
2051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2065e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev    pthread_mutex_unlock(&_r_debug_lock);
2075e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev}
2085e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
2095e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchevvoid notify_gdb_of_unload(soinfo * info)
2105e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev{
2115e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev    if (info->flags & FLAG_EXE) {
2125e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev        // GDB already knows about the main executable
2135e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev        return;
2145e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev    }
2155e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
2165e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev    pthread_mutex_lock(&_r_debug_lock);
2175e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
2185e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev    _r_debug.r_state = RT_DELETE;
2195e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev    rtld_db_dlactivity();
2205e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
2215e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev    remove_soinfo_from_debug_map(info);
2225e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
2235e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev    _r_debug.r_state = RT_CONSISTENT;
2245e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev    rtld_db_dlactivity();
2255e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
2265e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev    pthread_mutex_unlock(&_r_debug_lock);
2271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
2281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectvoid notify_gdb_of_libraries()
2301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
2311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    _r_debug.r_state = RT_ADD;
2321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    rtld_db_dlactivity();
2331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    _r_debug.r_state = RT_CONSISTENT;
2341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    rtld_db_dlactivity();
2351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
2361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic soinfo *alloc_info(const char *name)
2381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
2391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    soinfo *si;
2401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if(strlen(name) >= SOINFO_NAME_LEN) {
2422e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin        DL_ERR("%5d library name %s too long\n", pid, name);
2431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return 0;
2441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
2451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* The freelist is populated when we call free_info(), which in turn is
2471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project       done only by dlclose(), which is not likely to be used.
2481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    */
2491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (!freelist) {
2501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if(socount == SO_MAX) {
2512e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin            DL_ERR("%5d too many libraries when loading %s\n", pid, name);
2521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return NULL;
2531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
2541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        freelist = sopool + socount++;
2551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        freelist->next = NULL;
2561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
2571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si = freelist;
2591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    freelist = freelist->next;
2601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* Make sure we get a clean block of soinfo */
2621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    memset(si, 0, sizeof(soinfo));
2631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    strcpy((char*) si->name, name);
2641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    sonext->next = si;
2651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->ba_index = -1; /* by default, prelinked */
2661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->next = NULL;
2671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->refcount = 0;
2681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    sonext = si;
2691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    TRACE("%5d name %s: allocated soinfo @ %p\n", pid, name, si);
2711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return si;
2721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
2731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic void free_info(soinfo *si)
2751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
2761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    soinfo *prev = NULL, *trav;
2771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    TRACE("%5d name %s: freeing soinfo @ %p\n", pid, si->name, si);
2791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for(trav = solist; trav != NULL; trav = trav->next){
2811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (trav == si)
2821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
2831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        prev = trav;
2841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
2851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (trav == NULL) {
2861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        /* si was not ni solist */
2872e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin        DL_ERR("%5d name %s is not in solist!\n", pid, si->name);
2881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return;
2891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
2901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* prev will never be NULL, because the first entry in solist is
2921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project       always the static libdl_info.
2931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    */
2941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    prev->next = si->next;
2951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (si == sonext) sonext = prev;
2961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->next = freelist;
2971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    freelist = si;
2981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
2991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#ifndef LINKER_TEXT_BASE
3011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#error "linker's makefile must define LINKER_TEXT_BASE"
3021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
3031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#ifndef LINKER_AREA_SIZE
3041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#error "linker's makefile must define LINKER_AREA_SIZE"
3051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
3061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define LINKER_BASE ((LINKER_TEXT_BASE) & 0xfff00000)
3071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define LINKER_TOP  (LINKER_BASE + (LINKER_AREA_SIZE))
3081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectconst char *addr_to_name(unsigned addr)
3101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
3111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    soinfo *si;
3121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for(si = solist; si != 0; si = si->next){
3141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if((addr >= si->base) && (addr < (si->base + si->size))) {
3151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return si->name;
3161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
3171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
3181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if((addr >= LINKER_BASE) && (addr < LINKER_TOP)){
3201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return "linker";
3211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
3221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return "";
3241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
3251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* For a given PC, find the .so that it belongs to.
3271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Returns the base address of the .ARM.exidx section
3281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * for that .so, and the number of 8-byte entries
3291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * in that section (via *pcount).
3301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
3311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Intended to be called by libc's __gnu_Unwind_Find_exidx().
3321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
3331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * This function is exposed via dlfcn.c and libdl.so.
3341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
3351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#ifdef ANDROID_ARM_LINKER
3361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project_Unwind_Ptr dl_unwind_find_exidx(_Unwind_Ptr pc, int *pcount)
3371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
3381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    soinfo *si;
3391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned addr = (unsigned)pc;
3401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if ((addr < LINKER_BASE) || (addr >= LINKER_TOP)) {
3421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        for (si = solist; si != 0; si = si->next){
3431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if ((addr >= si->base) && (addr < (si->base + si->size))) {
3441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                *pcount = si->ARM_exidx_count;
3451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                return (_Unwind_Ptr)(si->base + (unsigned long)si->ARM_exidx);
3461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
3471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
3481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
3491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project   *pcount = 0;
3501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return NULL;
3511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
3521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#elif defined(ANDROID_X86_LINKER)
3531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* Here, we only have to provide a callback to iterate across all the
3541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * loaded libraries. gcc_eh does the rest. */
3551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint
3561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectdl_iterate_phdr(int (*cb)(struct dl_phdr_info *info, size_t size, void *data),
3571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                void *data)
3581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
3591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    soinfo *si;
3601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    struct dl_phdr_info dl_info;
3611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    int rv = 0;
3621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for (si = solist; si != NULL; si = si->next) {
3641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        dl_info.dlpi_addr = si->linkmap.l_addr;
3651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        dl_info.dlpi_name = si->linkmap.l_name;
3661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        dl_info.dlpi_phdr = si->phdr;
3671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        dl_info.dlpi_phnum = si->phnum;
3681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        rv = cb(&dl_info, sizeof (struct dl_phdr_info), data);
3691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (rv != 0)
3701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
3711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
3721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return rv;
3731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
3741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
3751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic Elf32_Sym *_elf_lookup(soinfo *si, unsigned hash, const char *name)
3771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
3781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Sym *s;
3791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Sym *symtab = si->symtab;
3801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    const char *strtab = si->strtab;
3811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned n;
3821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    TRACE_TYPE(LOOKUP, "%5d SEARCH %s in %s@0x%08x %08x %d\n", pid,
3841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project               name, si->name, si->base, hash, hash % si->nbucket);
3851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    n = hash % si->nbucket;
3861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for(n = si->bucket[hash % si->nbucket]; n != 0; n = si->chain[n]){
3881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        s = symtab + n;
3891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if(strcmp(strtab + s->st_name, name)) continue;
3901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            /* only concern ourselves with global symbols */
3921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        switch(ELF32_ST_BIND(s->st_info)){
3931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case STB_GLOBAL:
3941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                /* no section == undefined */
3951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if(s->st_shndx == 0) continue;
3961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case STB_WEAK:
3981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            TRACE_TYPE(LOOKUP, "%5d FOUND %s in %s (%08x) %d\n", pid,
3991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                       name, si->name, s->st_value, s->st_size);
4001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return s;
4011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
4021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
4031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
4041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return 0;
4051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
4061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
4071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic unsigned elfhash(const char *_name)
4081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
4091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    const unsigned char *name = (const unsigned char *) _name;
4101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned h = 0, g;
4111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
4121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    while(*name) {
4131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        h = (h << 4) + *name++;
4141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        g = h & 0xf0000000;
4151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        h ^= g;
4161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        h ^= g >> 24;
4171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
4181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return h;
4191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
4201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
4211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic Elf32_Sym *
4221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project_do_lookup_in_so(soinfo *si, const char *name, unsigned *elf_hash)
4231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
4241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (*elf_hash == 0)
4251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        *elf_hash = elfhash(name);
4261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return _elf_lookup (si, *elf_hash, name);
4271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
4281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
4291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* This is used by dl_sym() */
4301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source ProjectElf32_Sym *lookup_in_library(soinfo *si, const char *name)
4311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
4321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned unused = 0;
4331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return _do_lookup_in_so(si, name, &unused);
4341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
4351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
4361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic Elf32_Sym *
4371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project_do_lookup(soinfo *user_si, const char *name, unsigned *base)
4381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
4391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned elf_hash = 0;
4401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Sym *s = NULL;
4411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    soinfo *si;
4421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
4431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* Look for symbols in the local scope first (the object who is
4441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * searching). This happens with C++ templates on i386 for some
4451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * reason. */
4461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (user_si) {
4471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        s = _do_lookup_in_so(user_si, name, &elf_hash);
4481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (s != NULL)
4491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            *base = user_si->base;
4501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
4511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
4521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for(si = solist; (s == NULL) && (si != NULL); si = si->next)
4531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    {
4541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if((si->flags & FLAG_ERROR) || (si == user_si))
4551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            continue;
4561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        s = _do_lookup_in_so(si, name, &elf_hash);
4571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (s != NULL) {
4581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            *base = si->base;
4591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
4601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
4611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
4621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
4631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (s != NULL) {
4641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE_TYPE(LOOKUP, "%5d %s s->st_value = 0x%08x, "
4651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                   "si->base = 0x%08x\n", pid, name, s->st_value, si->base);
4661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return s;
4671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
4681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
4691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return 0;
4701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
4711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
4721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* This is used by dl_sym() */
4731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source ProjectElf32_Sym *lookup(const char *name, unsigned *base)
4741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
4751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return _do_lookup(NULL, name, base);
4761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
4771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
4781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if 0
4791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic void dump(soinfo *si)
4801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
4811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Sym *s = si->symtab;
4821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned n;
4831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
4841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for(n = 0; n < si->nchain; n++) {
4851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("%5d %04d> %08x: %02x %04x %08x %08x %s\n", pid, n, s,
4861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project               s->st_info, s->st_shndx, s->st_value, s->st_size,
4871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project               si->strtab + s->st_name);
4881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        s++;
4891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
4901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
4911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
4921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
4931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic const char *sopaths[] = {
4941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    "/system/lib",
4951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    "/lib",
4961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    0
4971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project};
4981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
4991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic int _open_lib(const char *name)
5001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
5011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    int fd;
5021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    struct stat filestat;
5031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if ((stat(name, &filestat) >= 0) && S_ISREG(filestat.st_mode)) {
5051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if ((fd = open(name, O_RDONLY)) >= 0)
5061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return fd;
5071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
5081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return -1;
5101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
5111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic int open_library(const char *name)
5131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
5141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    int fd;
5151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    char buf[512];
5161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    const char **path;
517bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley    int n;
5181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    TRACE("[ %5d opening %s ]\n", pid, name);
5201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if(name == 0) return -1;
5221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if(strlen(name) > 256) return -1;
5231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if ((name[0] == '/') && ((fd = _open_lib(name)) >= 0))
5251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return fd;
5261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
527bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley    for (path = ldpaths; *path; path++) {
528bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley        n = snprintf(buf, sizeof(buf), "%s/%s", *path, name);
529bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley        if (n < 0 || n >= (int)sizeof(buf)) {
530bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley            WARN("Ignoring very long library path: %s/%s\n", *path, name);
531bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley            continue;
532bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley        }
533bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley        if ((fd = _open_lib(buf)) >= 0)
534bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley            return fd;
535bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley    }
5361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for (path = sopaths; *path; path++) {
537bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley        n = snprintf(buf, sizeof(buf), "%s/%s", *path, name);
538bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley        if (n < 0 || n >= (int)sizeof(buf)) {
539bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley            WARN("Ignoring very long library path: %s/%s\n", *path, name);
540bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley            continue;
541bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley        }
5421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if ((fd = _open_lib(buf)) >= 0)
5431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return fd;
5441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
5451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return -1;
5471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
5481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* temporary space for holding the first page of the shared lib
5501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * which contains the elf header (with the pht). */
5511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic unsigned char __header[PAGE_SIZE];
5521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projecttypedef struct {
5541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    long mmap_addr;
5551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    char tag[4]; /* 'P', 'R', 'E', ' ' */
5561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} prelink_info_t;
5571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* Returns the requested base address if the library is prelinked,
5591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * and 0 otherwise.  */
5601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic unsigned long
5611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectis_prelinked(int fd, const char *name)
5621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
5631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    off_t sz;
5641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    prelink_info_t info;
5651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    sz = lseek(fd, -sizeof(prelink_info_t), SEEK_END);
5671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (sz < 0) {
5682e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin        DL_ERR("lseek() failed!\n");
5691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return 0;
5701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
5711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (read(fd, &info, sizeof(info)) != sizeof(info)) {
5731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        WARN("Could not read prelink_info_t structure for `%s`\n", name);
5741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return 0;
5751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
5761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (strncmp(info.tag, "PRE ", 4)) {
5781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        WARN("`%s` is not a prelinked library\n", name);
5791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return 0;
5801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
5811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return (unsigned long)info.mmap_addr;
5831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
5841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* verify_elf_object
5861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *      Verifies if the object @ base is a valid ELF object
5871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
5881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Args:
5891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
5901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Returns:
5911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *       0 on success
5921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *      -1 if no valid ELF object is found @ base.
5931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
5941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic int
5951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectverify_elf_object(void *base, const char *name)
5961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
5971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Ehdr *hdr = (Elf32_Ehdr *) base;
5981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (hdr->e_ident[EI_MAG0] != ELFMAG0) return -1;
6001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (hdr->e_ident[EI_MAG1] != ELFMAG1) return -1;
6011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (hdr->e_ident[EI_MAG2] != ELFMAG2) return -1;
6021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (hdr->e_ident[EI_MAG3] != ELFMAG3) return -1;
6031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* TODO: Should we verify anything else in the header? */
6051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return 0;
6071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
6081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* get_lib_extents
6111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *      Retrieves the base (*base) address where the ELF object should be
6121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *      mapped and its overall memory size (*total_sz).
6131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
6141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Args:
6151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *      fd: Opened file descriptor for the library
6161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *      name: The name of the library
6171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *      _hdr: Pointer to the header page of the library
6181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *      total_sz: Total size of the memory that should be allocated for
6191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *                this library
6201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
6211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Returns:
6221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *      -1 if there was an error while trying to get the lib extents.
6231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *         The possible reasons are:
6241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *             - Could not determine if the library was prelinked.
6251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *             - The library provided is not a valid ELF object
6261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *       0 if the library did not request a specific base offset (normal
6271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *         for non-prelinked libs)
6281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     > 0 if the library requests a specific address to be mapped to.
6291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *         This indicates a pre-linked library.
6301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
6311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic unsigned
6321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectget_lib_extents(int fd, const char *name, void *__hdr, unsigned *total_sz)
6331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
6341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned req_base;
6351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned min_vaddr = 0xffffffff;
6361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned max_vaddr = 0;
6371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned char *_hdr = (unsigned char *)__hdr;
6381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Ehdr *ehdr = (Elf32_Ehdr *)_hdr;
6391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Phdr *phdr;
6401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    int cnt;
6411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    TRACE("[ %5d Computing extents for '%s'. ]\n", pid, name);
6431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (verify_elf_object(_hdr, name) < 0) {
6442e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin        DL_ERR("%5d - %s is not a valid ELF object\n", pid, name);
6451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return (unsigned)-1;
6461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
6471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    req_base = (unsigned) is_prelinked(fd, name);
6491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (req_base == (unsigned)-1)
6501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return -1;
6511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    else if (req_base != 0) {
6521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d - Prelinked library '%s' requesting base @ 0x%08x ]\n",
6531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              pid, name, req_base);
6541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    } else {
6551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d - Non-prelinked library '%s' found. ]\n", pid, name);
6561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
6571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    phdr = (Elf32_Phdr *)(_hdr + ehdr->e_phoff);
6591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* find the min/max p_vaddrs from all the PT_LOAD segments so we can
6611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * get the range. */
6621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for (cnt = 0; cnt < ehdr->e_phnum; ++cnt, ++phdr) {
6631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (phdr->p_type == PT_LOAD) {
6641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if ((phdr->p_vaddr + phdr->p_memsz) > max_vaddr)
6651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                max_vaddr = phdr->p_vaddr + phdr->p_memsz;
6661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if (phdr->p_vaddr < min_vaddr)
6671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                min_vaddr = phdr->p_vaddr;
6681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
6691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
6701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if ((min_vaddr == 0xffffffff) && (max_vaddr == 0)) {
6722e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin        DL_ERR("%5d - No loadable segments found in %s.\n", pid, name);
6731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return (unsigned)-1;
6741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
6751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* truncate min_vaddr down to page boundary */
6771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    min_vaddr &= ~PAGE_MASK;
6781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* round max_vaddr up to the next page */
6801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    max_vaddr = (max_vaddr + PAGE_SIZE - 1) & ~PAGE_MASK;
6811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    *total_sz = (max_vaddr - min_vaddr);
6831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return (unsigned)req_base;
6841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
6851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* alloc_mem_region
6871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
6881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     This function reserves a chunk of memory to be used for mapping in
6891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     the shared library. We reserve the entire memory region here, and
6901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     then the rest of the linker will relocate the individual loadable
6911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     segments into the correct locations within this memory range.
6921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
6931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Args:
6941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     si->base: The requested base of the allocation. If 0, a sane one will be
6951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *               chosen in the range LIBBASE <= base < LIBLAST.
6961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     si->size: The size of the allocation.
6971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
6981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Returns:
6991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     -1 on failure, and 0 on success.  On success, si->base will contain
7001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     the virtual address at which the library will be mapped.
7011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
7021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
7031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic int reserve_mem_region(soinfo *si)
7041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
7051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    void *base = mmap((void *)si->base, si->size, PROT_READ | PROT_EXEC,
7061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                      MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
7071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (base == MAP_FAILED) {
7082e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin        DL_ERR("%5d can NOT map (%sprelinked) library '%s' at 0x%08x "
7091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              "as requested, will try general pool: %d (%s)\n",
7101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              pid, (si->base ? "" : "non-"), si->name, si->base,
7111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              errno, strerror(errno));
7121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return -1;
7131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    } else if (base != (void *)si->base) {
7142e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin        DL_ERR("OOPS: %5d %sprelinked library '%s' mapped at 0x%08x, "
7151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              "not at 0x%08x\n", pid, (si->base ? "" : "non-"),
7161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              si->name, (unsigned)base, si->base);
7171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        munmap(base, si->size);
7181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return -1;
7191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
7201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return 0;
7211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
7221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
7231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic int
7241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectalloc_mem_region(soinfo *si)
7251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
7261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (si->base) {
7271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        /* Attempt to mmap a prelinked library. */
7281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        si->ba_index = -1;
7291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return reserve_mem_region(si);
7301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
7311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
7321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* This is not a prelinked library, so we attempt to allocate space
7331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project       for it from the buddy allocator, which manages the area between
7341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project       LIBBASE and LIBLAST.
7351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    */
7361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->ba_index = ba_allocate(si->size);
7371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if(si->ba_index >= 0) {
7381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        si->base = ba_start_addr(si->ba_index);
7391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        PRINT("%5d mapping library '%s' at %08x (index %d) " \
7401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              "through buddy allocator.\n",
7411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              pid, si->name, si->base, si->ba_index);
7421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (reserve_mem_region(si) < 0) {
7431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            ba_free(si->ba_index);
7441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->ba_index = -1;
7451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->base = 0;
7461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            goto err;
7471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
7481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return 0;
7491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
7501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
7511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projecterr:
7522e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin    DL_ERR("OOPS: %5d cannot map library '%s'. no vspace available.\n",
7531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project          pid, si->name);
7541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return -1;
7551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
7561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
7571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define MAYBE_MAP_FLAG(x,from,to)    (((x) & (from)) ? (to) : 0)
7581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define PFLAGS_TO_PROT(x)            (MAYBE_MAP_FLAG((x), PF_X, PROT_EXEC) | \
7591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                                      MAYBE_MAP_FLAG((x), PF_R, PROT_READ) | \
7601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                                      MAYBE_MAP_FLAG((x), PF_W, PROT_WRITE))
7611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* load_segments
7621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
7631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     This function loads all the loadable (PT_LOAD) segments into memory
7641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     at their appropriate memory offsets off the base address.
7651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
7661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Args:
7671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     fd: Open file descriptor to the library to load.
7681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     header: Pointer to a header page that contains the ELF header.
7691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *             This is needed since we haven't mapped in the real file yet.
7701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     si: ptr to soinfo struct describing the shared object.
7711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
7721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Returns:
7731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     0 on success, -1 on failure.
7741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
7751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic int
7761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectload_segments(int fd, void *header, soinfo *si)
7771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
7781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Ehdr *ehdr = (Elf32_Ehdr *)header;
7791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Phdr *phdr = (Elf32_Phdr *)((unsigned char *)header + ehdr->e_phoff);
7801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned char *base = (unsigned char *)si->base;
7811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    int cnt;
7821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned len;
7831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned char *tmp;
7841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned char *pbase;
7851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned char *extra_base;
7861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned extra_len;
7871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned total_sz = 0;
7881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
7891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->wrprotect_start = 0xffffffff;
7901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->wrprotect_end = 0;
7911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
7921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    TRACE("[ %5d - Begin loading segments for '%s' @ 0x%08x ]\n",
7931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project          pid, si->name, (unsigned)si->base);
7941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* Now go through all the PT_LOAD segments and map them into memory
7951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * at the appropriate locations. */
7961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for (cnt = 0; cnt < ehdr->e_phnum; ++cnt, ++phdr) {
7971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (phdr->p_type == PT_LOAD) {
7981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            DEBUG_DUMP_PHDR(phdr, "PT_LOAD", pid);
7991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            /* we want to map in the segment on a page boundary */
8001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            tmp = base + (phdr->p_vaddr & (~PAGE_MASK));
8011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            /* add the # of bytes we masked off above to the total length. */
8021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            len = phdr->p_filesz + (phdr->p_vaddr & PAGE_MASK);
8031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
8041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            TRACE("[ %d - Trying to load segment from '%s' @ 0x%08x "
8051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                  "(0x%08x). p_vaddr=0x%08x p_offset=0x%08x ]\n", pid, si->name,
8061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                  (unsigned)tmp, len, phdr->p_vaddr, phdr->p_offset);
8071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            pbase = mmap(tmp, len, PFLAGS_TO_PROT(phdr->p_flags),
8081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                         MAP_PRIVATE | MAP_FIXED, fd,
8091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                         phdr->p_offset & (~PAGE_MASK));
8101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if (pbase == MAP_FAILED) {
8112e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin                DL_ERR("%d failed to map segment from '%s' @ 0x%08x (0x%08x). "
8121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                      "p_vaddr=0x%08x p_offset=0x%08x\n", pid, si->name,
8131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                      (unsigned)tmp, len, phdr->p_vaddr, phdr->p_offset);
8141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                goto fail;
8151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
8161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
8171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            /* If 'len' didn't end on page boundary, and it's a writable
8181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             * segment, zero-fill the rest. */
8191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if ((len & PAGE_MASK) && (phdr->p_flags & PF_W))
8201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                memset((void *)(pbase + len), 0, PAGE_SIZE - (len & PAGE_MASK));
8211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
8221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            /* Check to see if we need to extend the map for this segment to
8231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             * cover the diff between filesz and memsz (i.e. for bss).
8241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *
8251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *  base           _+---------------------+  page boundary
8261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *                  .                     .
8271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *                  |                     |
8281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *                  .                     .
8291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *  pbase          _+---------------------+  page boundary
8301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *                  |                     |
8311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *                  .                     .
8321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *  base + p_vaddr _|                     |
8331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *                  . \          \        .
8341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *                  . | filesz   |        .
8351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *  pbase + len    _| /          |        |
8361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *     <0 pad>      .            .        .
8371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *  extra_base     _+------------|--------+  page boundary
8381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *               /  .            .        .
8391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *               |  .            .        .
8401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *               |  +------------|--------+  page boundary
8411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *  extra_len->  |  |            |        |
8421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *               |  .            | memsz  .
8431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *               |  .            |        .
8441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *               \ _|            /        |
8451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *                  .                     .
8461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *                  |                     |
8471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *                 _+---------------------+  page boundary
8481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             */
8491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            tmp = (unsigned char *)(((unsigned)pbase + len + PAGE_SIZE - 1) &
8501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                                    (~PAGE_MASK));
8511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if (tmp < (base + phdr->p_vaddr + phdr->p_memsz)) {
8521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                extra_len = base + phdr->p_vaddr + phdr->p_memsz - tmp;
8531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                TRACE("[ %5d - Need to extend segment from '%s' @ 0x%08x "
8541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                      "(0x%08x) ]\n", pid, si->name, (unsigned)tmp, extra_len);
8551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                /* map in the extra page(s) as anonymous into the range.
8561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                 * This is probably not necessary as we already mapped in
8571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                 * the entire region previously, but we just want to be
8581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                 * sure. This will also set the right flags on the region
8591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                 * (though we can probably accomplish the same thing with
8601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                 * mprotect).
8611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                 */
8621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                extra_base = mmap((void *)tmp, extra_len,
8631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                                  PFLAGS_TO_PROT(phdr->p_flags),
8641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                                  MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS,
8651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                                  -1, 0);
8661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                if (extra_base == MAP_FAILED) {
8672e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin                    DL_ERR("[ %5d - failed to extend segment from '%s' @ 0x%08x"
8682e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin                           " (0x%08x) ]\n", pid, si->name, (unsigned)tmp,
8691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                          extra_len);
8701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    goto fail;
8711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                }
8721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                /* TODO: Check if we need to memset-0 this region.
8731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                 * Anonymous mappings are zero-filled copy-on-writes, so we
8741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                 * shouldn't need to. */
8751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                TRACE("[ %5d - Segment from '%s' extended @ 0x%08x "
8761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                      "(0x%08x)\n", pid, si->name, (unsigned)extra_base,
8771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                      extra_len);
8781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
8791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            /* set the len here to show the full extent of the segment we
8801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             * just loaded, mostly for debugging */
8811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            len = (((unsigned)base + phdr->p_vaddr + phdr->p_memsz +
8821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    PAGE_SIZE - 1) & (~PAGE_MASK)) - (unsigned)pbase;
8831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            TRACE("[ %5d - Successfully loaded segment from '%s' @ 0x%08x "
8841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                  "(0x%08x). p_vaddr=0x%08x p_offset=0x%08x\n", pid, si->name,
8851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                  (unsigned)pbase, len, phdr->p_vaddr, phdr->p_offset);
8861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            total_sz += len;
8871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            /* Make the section writable just in case we'll have to write to
8881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             * it during relocation (i.e. text segment). However, we will
8891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             * remember what range of addresses should be write protected.
8901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *
8911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             */
8921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if (!(phdr->p_flags & PF_W)) {
8931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                if ((unsigned)pbase < si->wrprotect_start)
8941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    si->wrprotect_start = (unsigned)pbase;
8951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                if (((unsigned)pbase + len) > si->wrprotect_end)
8961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    si->wrprotect_end = (unsigned)pbase + len;
8971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                mprotect(pbase, len,
8981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                         PFLAGS_TO_PROT(phdr->p_flags) | PROT_WRITE);
8991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
9001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        } else if (phdr->p_type == PT_DYNAMIC) {
9011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            DEBUG_DUMP_PHDR(phdr, "PT_DYNAMIC", pid);
9021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            /* this segment contains the dynamic linking information */
9031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->dynamic = (unsigned *)(base + phdr->p_vaddr);
9041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        } else {
9051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#ifdef ANDROID_ARM_LINKER
9061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if (phdr->p_type == PT_ARM_EXIDX) {
9071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                DEBUG_DUMP_PHDR(phdr, "PT_ARM_EXIDX", pid);
9081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                /* exidx entries (used for stack unwinding) are 8 bytes each.
9091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                 */
9101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                si->ARM_exidx = (unsigned *)phdr->p_vaddr;
9111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                si->ARM_exidx_count = phdr->p_memsz / 8;
9121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
9131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
9141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
9151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
9161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
9171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
9181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* Sanity check */
9191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (total_sz > si->size) {
9202e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin        DL_ERR("%5d - Total length (0x%08x) of mapped segments from '%s' is "
9211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              "greater than what was allocated (0x%08x). THIS IS BAD!\n",
9221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              pid, total_sz, si->name, si->size);
9231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        goto fail;
9241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
9251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
9261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    TRACE("[ %5d - Finish loading segments for '%s' @ 0x%08x. "
9271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project          "Total memory footprint: 0x%08x bytes ]\n", pid, si->name,
9281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project          (unsigned)si->base, si->size);
9291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return 0;
9301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
9311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectfail:
9321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* We can just blindly unmap the entire region even though some things
9331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * were mapped in originally with anonymous and others could have been
9341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * been mapped in from the file before we failed. The kernel will unmap
9351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * all the pages in the range, irrespective of how they got there.
9361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     */
9371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    munmap((void *)si->base, si->size);
9381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->flags |= FLAG_ERROR;
9391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return -1;
9401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
9411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
9421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* TODO: Implement this to take care of the fact that Android ARM
9431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * ELF objects shove everything into a single loadable segment that has the
9441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * write bit set. wr_offset is then used to set non-(data|bss) pages to be
9451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * non-writable.
9461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
9471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if 0
9481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic unsigned
9491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectget_wr_offset(int fd, const char *name, Elf32_Ehdr *ehdr)
9501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
9511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Shdr *shdr_start;
9521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Shdr *shdr;
9531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    int shdr_sz = ehdr->e_shnum * sizeof(Elf32_Shdr);
9541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    int cnt;
9551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned wr_offset = 0xffffffff;
9561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
9571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    shdr_start = mmap(0, shdr_sz, PROT_READ, MAP_PRIVATE, fd,
9581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                      ehdr->e_shoff & (~PAGE_MASK));
9591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (shdr_start == MAP_FAILED) {
9601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        WARN("%5d - Could not read section header info from '%s'. Will not "
9611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             "not be able to determine write-protect offset.\n", pid, name);
9621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return (unsigned)-1;
9631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
9641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
9651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for(cnt = 0, shdr = shdr_start; cnt < ehdr->e_shnum; ++cnt, ++shdr) {
9661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if ((shdr->sh_type != SHT_NULL) && (shdr->sh_flags & SHF_WRITE) &&
9671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            (shdr->sh_addr < wr_offset)) {
9681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            wr_offset = shdr->sh_addr;
9691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
9701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
9711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
9721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    munmap(shdr_start, shdr_sz);
9731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return wr_offset;
9741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
9751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
9761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
9771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic soinfo *
9781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectload_library(const char *name)
9791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
9801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    int fd = open_library(name);
9811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    int cnt;
9821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned ext_sz;
9831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned req_base;
9841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    soinfo *si = NULL;
9851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Ehdr *hdr;
9861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
9872e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin    if(fd == -1) {
9882e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin        DL_ERR("Library '%s' not found\n", name);
9891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return NULL;
9902e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin    }
9911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
9921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* We have to read the ELF header to figure out what to do with this image
9931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     */
9941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (lseek(fd, 0, SEEK_SET) < 0) {
9952e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin        DL_ERR("lseek() failed!\n");
9961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        goto fail;
9971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
9981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
9991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if ((cnt = read(fd, &__header[0], PAGE_SIZE)) < 0) {
10002e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin        DL_ERR("read() failed!\n");
10011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        goto fail;
10021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
10031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* Parse the ELF header and get the size of the memory footprint for
10051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * the library */
10061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    req_base = get_lib_extents(fd, name, &__header[0], &ext_sz);
10071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (req_base == (unsigned)-1)
10081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        goto fail;
10091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    TRACE("[ %5d - '%s' (%s) wants base=0x%08x sz=0x%08x ]\n", pid, name,
10101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project          (req_base ? "prelinked" : "not pre-linked"), req_base, ext_sz);
10111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* Now configure the soinfo struct where we'll store all of our data
10131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * for the ELF object. If the loading fails, we waste the entry, but
10141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * same thing would happen if we failed during linking. Configuring the
10151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * soinfo struct here is a lot more convenient.
10161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     */
10171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si = alloc_info(name);
10181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (si == NULL)
10191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        goto fail;
10201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* Carve out a chunk of memory where we will map in the individual
10221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * segments */
10231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->base = req_base;
10241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->size = ext_sz;
10251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->flags = 0;
10261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->entry = 0;
10271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->dynamic = (unsigned *)-1;
10281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (alloc_mem_region(si) < 0)
10291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        goto fail;
10301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    TRACE("[ %5d allocated memory for %s @ %p (0x%08x) ]\n",
10321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project          pid, name, (void *)si->base, (unsigned) ext_sz);
10331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* Now actually load the library's segments into right places in memory */
10351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (load_segments(fd, &__header[0], si) < 0) {
10361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (si->ba_index >= 0) {
10371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            ba_free(si->ba_index);
10381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->ba_index = -1;
10391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
10401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        goto fail;
10411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
10421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* this might not be right. Technically, we don't even need this info
10441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * once we go through 'load_segments'. */
10451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    hdr = (Elf32_Ehdr *)si->base;
10461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->phdr = (Elf32_Phdr *)((unsigned char *)si->base + hdr->e_phoff);
10471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->phnum = hdr->e_phnum;
10481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /**/
10491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    close(fd);
10511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return si;
10521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectfail:
10541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (si) free_info(si);
10551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    close(fd);
10561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return NULL;
10571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
10581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic soinfo *
10601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectinit_library(soinfo *si)
10611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
10621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned wr_offset = 0xffffffff;
10631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* At this point we know that whatever is loaded @ base is a valid ELF
10651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * shared library whose segments are properly mapped in. */
10661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    TRACE("[ %5d init_library base=0x%08x sz=0x%08x name='%s') ]\n",
10671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project          pid, si->base, si->size, si->name);
10681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (si->base < LIBBASE || si->base >= LIBLAST)
10701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        si->flags |= FLAG_PRELINKED;
10711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if(link_image(si, wr_offset)) {
10731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            /* We failed to link.  However, we can only restore libbase
10741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            ** if no additional libraries have moved it since we updated it.
10751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            */
10761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        munmap((void *)si->base, si->size);
10771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return NULL;
10781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
10791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return si;
10811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
10821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectsoinfo *find_library(const char *name)
10841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
10851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    soinfo *si;
10861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for(si = solist; si != 0; si = si->next){
10881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if(!strcmp(name, si->name)) {
10891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if(si->flags & FLAG_ERROR) return 0;
10901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if(si->flags & FLAG_LINKED) return si;
10912e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin            DL_ERR("OOPS: %5d recursive link to '%s'\n", pid, si->name);
10922e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin            return NULL;
10931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
10941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
10951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    TRACE("[ %5d '%s' has not been loaded yet.  Locating...]\n", pid, name);
10971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si = load_library(name);
10981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if(si == NULL)
10991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return NULL;
11001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return init_library(si);
11011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
11021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
11031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* TODO:
11041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *   notify gdb of unload
11051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *   for non-prelinked libraries, find a way to decrement libbase
11061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
11071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic void call_destructors(soinfo *si);
11081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectunsigned unload_library(soinfo *si)
11091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
11101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned *d;
11111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (si->refcount == 1) {
11121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("%5d unloading '%s'\n", pid, si->name);
11131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        call_destructors(si);
11141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
11151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        for(d = si->dynamic; *d; d += 2) {
11161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if(d[0] == DT_NEEDED){
11171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                TRACE("%5d %s needs to unload %s\n", pid,
11181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                      si->name, si->strtab + d[1]);
11191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                soinfo *lsi = find_library(si->strtab + d[1]);
11201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                if(lsi)
11211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    unload_library(lsi);
11221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                else
11232e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin                    DL_ERR("%5d could not unload '%s'\n",
11241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                          pid, si->strtab + d[1]);
11251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
11261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
11271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
11281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        munmap((char *)si->base, si->size);
11291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (si->ba_index >= 0) {
11301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            PRINT("%5d releasing library '%s' address space at %08x "\
11311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                  "through buddy allocator.\n",
11321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                  pid, si->name, si->base);
11331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            ba_free(si->ba_index);
11341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
11355e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev        notify_gdb_of_unload(si);
11361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        free_info(si);
11371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        si->refcount = 0;
11381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
11391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    else {
11401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        si->refcount--;
11411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        PRINT("%5d not unloading '%s', decrementing refcount to %d\n",
11421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              pid, si->name, si->refcount);
11431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
11441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return si->refcount;
11451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
11461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
11471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* TODO: don't use unsigned for addrs below. It works, but is not
11481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * ideal. They should probably be either uint32_t, Elf32_Addr, or unsigned
11491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * long.
11501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
11511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic int reloc_library(soinfo *si, Elf32_Rel *rel, unsigned count)
11521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
11531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Sym *symtab = si->symtab;
11541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    const char *strtab = si->strtab;
11551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Sym *s;
11561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned base;
11571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Rel *start = rel;
11581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned idx;
11591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
11601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for (idx = 0; idx < count; ++idx) {
11611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        unsigned type = ELF32_R_TYPE(rel->r_info);
11621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        unsigned sym = ELF32_R_SYM(rel->r_info);
11631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        unsigned reloc = (unsigned)(rel->r_offset + si->base);
11641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        unsigned sym_addr = 0;
11651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        char *sym_name = NULL;
11661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
11671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        DEBUG("%5d Processing '%s' relocation at index %d\n", pid,
11681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              si->name, idx);
11691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if(sym != 0) {
1170d1b40d8c69dfca94185ea9231f6cb16f70c02e39Dima Zavin            sym_name = (char *)(strtab + symtab[sym].st_name);
1171d1b40d8c69dfca94185ea9231f6cb16f70c02e39Dima Zavin            s = _do_lookup(si, sym_name, &base);
11721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if(s == 0) {
11732e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin                DL_ERR("%5d cannot locate '%s'...\n", pid, sym_name);
11741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                return -1;
11751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
11761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if 0
11771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if((base == 0) && (si->base != 0)){
11781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    /* linking from libraries to main image is bad */
11792e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin                DL_ERR("%5d cannot locate '%s'...\n",
11801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                       pid, strtab + symtab[sym].st_name);
11811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                return -1;
11821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
11831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
11841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if ((s->st_shndx == SHN_UNDEF) && (s->st_value != 0)) {
11852e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin                DL_ERR("%5d In '%s', shndx=%d && value=0x%08x. We do not "
11861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                      "handle this yet\n", pid, si->name, s->st_shndx,
11871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                      s->st_value);
11881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                return -1;
11891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
11901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            sym_addr = (unsigned)(s->st_value + base);
11911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            COUNT_RELOC(RELOC_SYMBOL);
11921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        } else {
11931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            s = 0;
11941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
11951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
11961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* TODO: This is ugly. Split up the relocations by arch into
11971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * different files.
11981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
11991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        switch(type){
12001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if defined(ANDROID_ARM_LINKER)
12011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case R_ARM_JUMP_SLOT:
12021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            COUNT_RELOC(RELOC_ABSOLUTE);
12031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            MARK(rel->r_offset);
12041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            TRACE_TYPE(RELO, "%5d RELO JMP_SLOT %08x <- %08x %s\n", pid,
12051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                       reloc, sym_addr, sym_name);
12061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            *((unsigned*)reloc) = sym_addr;
12071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
12081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case R_ARM_GLOB_DAT:
12091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            COUNT_RELOC(RELOC_ABSOLUTE);
12101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            MARK(rel->r_offset);
12111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            TRACE_TYPE(RELO, "%5d RELO GLOB_DAT %08x <- %08x %s\n", pid,
12121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                       reloc, sym_addr, sym_name);
12131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            *((unsigned*)reloc) = sym_addr;
12141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
12151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case R_ARM_ABS32:
12161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            COUNT_RELOC(RELOC_ABSOLUTE);
12171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            MARK(rel->r_offset);
12181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            TRACE_TYPE(RELO, "%5d RELO ABS %08x <- %08x %s\n", pid,
12191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                       reloc, sym_addr, sym_name);
12201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            *((unsigned*)reloc) += sym_addr;
12211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
12221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#elif defined(ANDROID_X86_LINKER)
12231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case R_386_JUMP_SLOT:
12241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            COUNT_RELOC(RELOC_ABSOLUTE);
12251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            MARK(rel->r_offset);
12261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            TRACE_TYPE(RELO, "%5d RELO JMP_SLOT %08x <- %08x %s\n", pid,
12271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                       reloc, sym_addr, sym_name);
12281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            *((unsigned*)reloc) = sym_addr;
12291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
12301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case R_386_GLOB_DAT:
12311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            COUNT_RELOC(RELOC_ABSOLUTE);
12321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            MARK(rel->r_offset);
12331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            TRACE_TYPE(RELO, "%5d RELO GLOB_DAT %08x <- %08x %s\n", pid,
12341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                       reloc, sym_addr, sym_name);
12351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            *((unsigned*)reloc) = sym_addr;
12361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
12371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif /* ANDROID_*_LINKER */
12381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
12391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if defined(ANDROID_ARM_LINKER)
12401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case R_ARM_RELATIVE:
12411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#elif defined(ANDROID_X86_LINKER)
12421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case R_386_RELATIVE:
12431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif /* ANDROID_*_LINKER */
12441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            COUNT_RELOC(RELOC_RELATIVE);
12451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            MARK(rel->r_offset);
12461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if(sym){
12472e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin                DL_ERR("%5d odd RELATIVE form...\n", pid);
12481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                return -1;
12491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
12501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            TRACE_TYPE(RELO, "%5d RELO RELATIVE %08x <- +%08x\n", pid,
12511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                       reloc, si->base);
12521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            *((unsigned*)reloc) += si->base;
12531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
12541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
12551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if defined(ANDROID_X86_LINKER)
12561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case R_386_32:
12571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            COUNT_RELOC(RELOC_RELATIVE);
12581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            MARK(rel->r_offset);
12591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
12601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            TRACE_TYPE(RELO, "%5d RELO R_386_32 %08x <- +%08x %s\n", pid,
12611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                       reloc, sym_addr, sym_name);
12621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            *((unsigned *)reloc) += (unsigned)sym_addr;
12631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
12641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
12651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case R_386_PC32:
12661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            COUNT_RELOC(RELOC_RELATIVE);
12671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            MARK(rel->r_offset);
12681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            TRACE_TYPE(RELO, "%5d RELO R_386_PC32 %08x <- "
12691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                       "+%08x (%08x - %08x) %s\n", pid, reloc,
12701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                       (sym_addr - reloc), sym_addr, reloc, sym_name);
12711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            *((unsigned *)reloc) += (unsigned)(sym_addr - reloc);
12721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
12731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif /* ANDROID_X86_LINKER */
12741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
12751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#ifdef ANDROID_ARM_LINKER
12761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case R_ARM_COPY:
12771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            COUNT_RELOC(RELOC_COPY);
12781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            MARK(rel->r_offset);
12791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            TRACE_TYPE(RELO, "%5d RELO %08x <- %d @ %08x %s\n", pid,
12801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                       reloc, s->st_size, sym_addr, sym_name);
12811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            memcpy((void*)reloc, (void*)sym_addr, s->st_size);
12821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
12835e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev        case R_ARM_NONE:
12845e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev            break;
12851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif /* ANDROID_ARM_LINKER */
12861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
12871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        default:
12882e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin            DL_ERR("%5d unknown reloc type %d @ %p (%d)\n",
12891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                  pid, type, rel, (int) (rel - start));
12901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return -1;
12911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
12921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        rel++;
12931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
12941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return 0;
12951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
12961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
12978215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner
12988215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner/* Please read the "Initialization and Termination functions" functions.
12998215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner * of the linker design note in bionic/linker/README.TXT to understand
13008215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner * what the following code is doing.
13018215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner *
13028215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner * The important things to remember are:
13038215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner *
13048215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner *   DT_PREINIT_ARRAY must be called first for executables, and should
13058215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner *   not appear in shared libraries.
13068215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner *
13078215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner *   DT_INIT should be called before DT_INIT_ARRAY if both are present
13088215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner *
13098215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner *   DT_FINI should be called after DT_FINI_ARRAY if both are present
13108215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner *
13118215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner *   DT_FINI_ARRAY must be parsed in reverse order.
13128215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner */
13138215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner
13148215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turnerstatic void call_array(unsigned *ctor, int count, int reverse)
13151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
13168215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner    int n, inc = 1;
13178215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner
13188215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner    if (reverse) {
13198215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner        ctor += (count-1);
13208215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner        inc   = -1;
13218215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner    }
13228215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner
13238215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner    for(n = count; n > 0; n--) {
13248215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner        TRACE("[ %5d Looking at %s *0x%08x == 0x%08x ]\n", pid,
13258215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner              reverse ? "dtor" : "ctor",
13261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              (unsigned)ctor, (unsigned)*ctor);
13278215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner        void (*func)() = (void (*)()) *ctor;
13288215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner        ctor += inc;
13291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if(((int) func == 0) || ((int) func == -1)) continue;
13301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d Calling func @ 0x%08x ]\n", pid, (unsigned)func);
13311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        func();
13321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
13331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
13341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
13351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic void call_constructors(soinfo *si)
13361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
13371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (si->flags & FLAG_EXE) {
13381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d Calling preinit_array @ 0x%08x [%d] for '%s' ]\n",
13391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              pid, (unsigned)si->preinit_array, si->preinit_array_count,
13401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              si->name);
13418215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner        call_array(si->preinit_array, si->preinit_array_count, 0);
13421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d Done calling preinit_array for '%s' ]\n", pid, si->name);
13431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    } else {
13441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (si->preinit_array) {
13452e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin            DL_ERR("%5d Shared library '%s' has a preinit_array table @ 0x%08x."
13462e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin                   " This is INVALID.\n", pid, si->name,
13472e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin                   (unsigned)si->preinit_array);
13481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
13491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
13501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
13511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (si->init_func) {
13521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d Calling init_func @ 0x%08x for '%s' ]\n", pid,
13531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              (unsigned)si->init_func, si->name);
13541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        si->init_func();
13551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d Done calling init_func for '%s' ]\n", pid, si->name);
13561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
13571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
13581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (si->init_array) {
13591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d Calling init_array @ 0x%08x [%d] for '%s' ]\n", pid,
13601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              (unsigned)si->init_array, si->init_array_count, si->name);
13618215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner        call_array(si->init_array, si->init_array_count, 0);
13621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d Done calling init_array for '%s' ]\n", pid, si->name);
13631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
13641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
13651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
13668215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner
13671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic void call_destructors(soinfo *si)
13681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
13691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (si->fini_array) {
13701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d Calling fini_array @ 0x%08x [%d] for '%s' ]\n", pid,
13711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              (unsigned)si->fini_array, si->fini_array_count, si->name);
13728215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner        call_array(si->fini_array, si->fini_array_count, 1);
13731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d Done calling fini_array for '%s' ]\n", pid, si->name);
13741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
13751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
13761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (si->fini_func) {
13771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d Calling fini_func @ 0x%08x for '%s' ]\n", pid,
13781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              (unsigned)si->fini_func, si->name);
13791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        si->fini_func();
13801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d Done calling fini_func for '%s' ]\n", pid, si->name);
13811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
13821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
13831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
13841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* Force any of the closed stdin, stdout and stderr to be associated with
13851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project   /dev/null. */
13861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic int nullify_closed_stdio (void)
13871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
13881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    int dev_null, i, status;
13891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    int return_value = 0;
13901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
13911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    dev_null = open("/dev/null", O_RDWR);
13921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (dev_null < 0) {
13932e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin        DL_ERR("Cannot open /dev/null.\n");
13941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return -1;
13951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
13961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    TRACE("[ %5d Opened /dev/null file-descriptor=%d]\n", pid, dev_null);
13971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
13981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* If any of the stdio file descriptors is valid and not associated
13991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project       with /dev/null, dup /dev/null to it.  */
14001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for (i = 0; i < 3; i++) {
14011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        /* If it is /dev/null already, we are done. */
14021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (i == dev_null)
14031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            continue;
14041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
14051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d Nullifying stdio file descriptor %d]\n", pid, i);
14061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        /* The man page of fcntl does not say that fcntl(..,F_GETFL)
14071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project           can be interrupted but we do this just to be safe. */
14081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        do {
14091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project          status = fcntl(i, F_GETFL);
14101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        } while (status < 0 && errno == EINTR);
14111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
14121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        /* If file is openned, we are good. */
14131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (status >= 0)
14141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project          continue;
14151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
14161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        /* The only error we allow is that the file descriptor does not
14171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project           exist, in which case we dup /dev/null to it. */
14181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (errno != EBADF) {
14192e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin            DL_ERR("nullify_stdio: unhandled error %s\n", strerror(errno));
14201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return_value = -1;
14211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            continue;
14221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
14231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
14241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        /* Try dupping /dev/null to this stdio file descriptor and
14251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project           repeat if there is a signal.  Note that any errors in closing
14261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project           the stdio descriptor are lost.  */
14271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        do {
14281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            status = dup2(dev_null, i);
14291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        } while (status < 0 && errno == EINTR);
14302e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin
14311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (status < 0) {
14322e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin            DL_ERR("nullify_stdio: dup2 error %s\n", strerror(errno));
14331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return_value = -1;
14341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            continue;
14351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
14361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
14371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
14381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* If /dev/null is not one of the stdio file descriptors, close it. */
14391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (dev_null > 2) {
14401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d Closing /dev/null file-descriptor=%d]\n", pid, dev_null);
14412e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin        do {
14421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            status = close(dev_null);
14431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        } while (status < 0 && errno == EINTR);
14441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
14451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (status < 0) {
14462e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin            DL_ERR("nullify_stdio: close error %s\n", strerror(errno));
14471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return_value = -1;
14481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
14491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
14501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
14511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return return_value;
14521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
14531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
14541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic int link_image(soinfo *si, unsigned wr_offset)
14551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
14561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned *d;
14571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Phdr *phdr = si->phdr;
14581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    int phnum = si->phnum;
14591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
14601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    INFO("[ %5d linking %s ]\n", pid, si->name);
14611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    DEBUG("%5d si->base = 0x%08x si->flags = 0x%08x\n", pid,
14621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project          si->base, si->flags);
14631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
14641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (si->flags & FLAG_EXE) {
14651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        /* Locate the needed program segments (DYNAMIC/ARM_EXIDX) for
14661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project         * linkage info if this is the executable. If this was a
14671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project         * dynamic lib, that would have been done at load time.
14681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project         *
14691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project         * TODO: It's unfortunate that small pieces of this are
14701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project         * repeated from the load_library routine. Refactor this just
14711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project         * slightly to reuse these bits.
14721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project         */
14731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        si->size = 0;
14741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        for(; phnum > 0; --phnum, ++phdr) {
14751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#ifdef ANDROID_ARM_LINKER
14761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if(phdr->p_type == PT_ARM_EXIDX) {
14771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                /* exidx entries (used for stack unwinding) are 8 bytes each.
14781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                 */
14791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                si->ARM_exidx = (unsigned *)phdr->p_vaddr;
14801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                si->ARM_exidx_count = phdr->p_memsz / 8;
14811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
14821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
14831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if (phdr->p_type == PT_LOAD) {
14841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                /* For the executable, we use the si->size field only in
14851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                   dl_unwind_find_exidx(), so the meaning of si->size
14861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                   is not the size of the executable; it is the last
14871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                   virtual address of the loadable part of the executable;
14881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                   since si->base == 0 for an executable, we use the
14891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                   range [0, si->size) to determine whether a PC value
14901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                   falls within the executable section.  Of course, if
14911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                   a value is below phdr->p_vaddr, it's not in the
14921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                   executable section, but a) we shouldn't be asking for
14931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                   such a value anyway, and b) if we have to provide
14941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                   an EXIDX for such a value, then the executable's
14951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                   EXIDX is probably the better choice.
14961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                */
14971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                DEBUG_DUMP_PHDR(phdr, "PT_LOAD", pid);
14981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                if (phdr->p_vaddr + phdr->p_memsz > si->size)
14991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    si->size = phdr->p_vaddr + phdr->p_memsz;
15001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                /* try to remember what range of addresses should be write
15011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                 * protected */
15021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                if (!(phdr->p_flags & PF_W)) {
15031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    unsigned _end;
15041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
15051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    if (phdr->p_vaddr < si->wrprotect_start)
15061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                        si->wrprotect_start = phdr->p_vaddr;
15071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    _end = (((phdr->p_vaddr + phdr->p_memsz + PAGE_SIZE - 1) &
15081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                             (~PAGE_MASK)));
15091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    if (_end > si->wrprotect_end)
15101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                        si->wrprotect_end = _end;
15111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                }
15121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            } else if (phdr->p_type == PT_DYNAMIC) {
15131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                if (si->dynamic != (unsigned *)-1) {
15142e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin                    DL_ERR("%5d multiple PT_DYNAMIC segments found in '%s'. "
15151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                          "Segment at 0x%08x, previously one found at 0x%08x\n",
15161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                          pid, si->name, si->base + phdr->p_vaddr,
15171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                          (unsigned)si->dynamic);
15181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    goto fail;
15191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                }
15201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                DEBUG_DUMP_PHDR(phdr, "PT_DYNAMIC", pid);
15211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                si->dynamic = (unsigned *) (si->base + phdr->p_vaddr);
15221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
15231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
15241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
15251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
15261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (si->dynamic == (unsigned *)-1) {
15272e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin        DL_ERR("%5d missing PT_DYNAMIC?!\n", pid);
15281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        goto fail;
15291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
15301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
15311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    DEBUG("%5d dynamic = %p\n", pid, si->dynamic);
15321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
15331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* extract useful information from dynamic section */
15341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for(d = si->dynamic; *d; d++){
15351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        DEBUG("%5d d = %p, d[0] = 0x%08x d[1] = 0x%08x\n", pid, d, d[0], d[1]);
15361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        switch(*d++){
15371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_HASH:
15381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->nbucket = ((unsigned *) (si->base + *d))[0];
15391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->nchain = ((unsigned *) (si->base + *d))[1];
15401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->bucket = (unsigned *) (si->base + *d + 8);
15411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->chain = (unsigned *) (si->base + *d + 8 + si->nbucket * 4);
15421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
15431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_STRTAB:
15441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->strtab = (const char *) (si->base + *d);
15451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
15461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_SYMTAB:
15471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->symtab = (Elf32_Sym *) (si->base + *d);
15481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
15491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_PLTREL:
15501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if(*d != DT_REL) {
15512e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin                DL_ERR("DT_RELA not supported\n");
15521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                goto fail;
15531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
15541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
15551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_JMPREL:
15561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->plt_rel = (Elf32_Rel*) (si->base + *d);
15571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
15581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_PLTRELSZ:
15591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->plt_rel_count = *d / 8;
15601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
15611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_REL:
15621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->rel = (Elf32_Rel*) (si->base + *d);
15631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
15641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_RELSZ:
15651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->rel_count = *d / 8;
15661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
15671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_PLTGOT:
15681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            /* Save this in case we decide to do lazy binding. We don't yet. */
15691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->plt_got = (unsigned *)(si->base + *d);
15701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
15711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_DEBUG:
15721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            // Set the DT_DEBUG entry to the addres of _r_debug for GDB
15731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            *d = (int) &_r_debug;
15741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
15751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_RELA:
15762e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin            DL_ERR("%5d DT_RELA not supported\n", pid);
15771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            goto fail;
15781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_INIT:
15791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->init_func = (void (*)(void))(si->base + *d);
15801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            DEBUG("%5d %s constructors (init func) found at %p\n",
15811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                  pid, si->name, si->init_func);
15821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
15831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_FINI:
15841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->fini_func = (void (*)(void))(si->base + *d);
15851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            DEBUG("%5d %s destructors (fini func) found at %p\n",
15861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                  pid, si->name, si->fini_func);
15871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
15881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_INIT_ARRAY:
15891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->init_array = (unsigned *)(si->base + *d);
15901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            DEBUG("%5d %s constructors (init_array) found at %p\n",
15911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                  pid, si->name, si->init_array);
15921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
15931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_INIT_ARRAYSZ:
15941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->init_array_count = ((unsigned)*d) / sizeof(Elf32_Addr);
15951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
15961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_FINI_ARRAY:
15971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->fini_array = (unsigned *)(si->base + *d);
15981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            DEBUG("%5d %s destructors (fini_array) found at %p\n",
15991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                  pid, si->name, si->fini_array);
16001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
16011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_FINI_ARRAYSZ:
16021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->fini_array_count = ((unsigned)*d) / sizeof(Elf32_Addr);
16031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
16041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_PREINIT_ARRAY:
16051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->preinit_array = (unsigned *)(si->base + *d);
16061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            DEBUG("%5d %s constructors (preinit_array) found at %p\n",
16071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                  pid, si->name, si->preinit_array);
16081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
16091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_PREINIT_ARRAYSZ:
16101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->preinit_array_count = ((unsigned)*d) / sizeof(Elf32_Addr);
16111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
16121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_TEXTREL:
16131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            /* TODO: make use of this. */
16141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            /* this means that we might have to write into where the text
16151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             * segment was loaded during relocation... Do something with
16161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             * it.
16171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             */
16181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            DEBUG("%5d Text segment should be writable during relocation.\n",
16191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                  pid);
16201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
16211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
16221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
16231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
16241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    DEBUG("%5d si->base = 0x%08x, si->strtab = %p, si->symtab = %p\n",
16251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project           pid, si->base, si->strtab, si->symtab);
16261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
16271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if((si->strtab == 0) || (si->symtab == 0)) {
16282e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin        DL_ERR("%5d missing essential tables\n", pid);
16291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        goto fail;
16301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
16311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
16321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for(d = si->dynamic; *d; d += 2) {
16331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if(d[0] == DT_NEEDED){
16341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            DEBUG("%5d %s needs %s\n", pid, si->name, si->strtab + d[1]);
16352e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin            soinfo *lsi = find_library(si->strtab + d[1]);
16361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if(lsi == 0) {
16370353195f344666256dba474a15c9ba22cf0cccc9Dima Zavin                strlcpy(tmp_err_buf, linker_get_error(), sizeof(tmp_err_buf));
16380353195f344666256dba474a15c9ba22cf0cccc9Dima Zavin                DL_ERR("%5d could not load needed library '%s' for '%s' (%s)\n",
16390353195f344666256dba474a15c9ba22cf0cccc9Dima Zavin                       pid, si->strtab + d[1], si->name, tmp_err_buf);
16401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                goto fail;
16411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
16421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            lsi->refcount++;
16431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
16441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
16451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
16461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if(si->plt_rel) {
16471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        DEBUG("[ %5d relocating %s plt ]\n", pid, si->name );
16481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if(reloc_library(si, si->plt_rel, si->plt_rel_count))
16491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            goto fail;
16501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
16511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if(si->rel) {
16521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        DEBUG("[ %5d relocating %s ]\n", pid, si->name );
16531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if(reloc_library(si, si->rel, si->rel_count))
16541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            goto fail;
16551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
16561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
16571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->flags |= FLAG_LINKED;
16581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    DEBUG("[ %5d finished linking %s ]\n", pid, si->name);
16591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
16601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if 0
16611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* This is the way that the old dynamic linker did protection of
16621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * non-writable areas. It would scan section headers and find where
16631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * .text ended (rather where .data/.bss began) and assume that this is
16641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * the upper range of the non-writable area. This is too coarse,
16651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * and is kept here for reference until we fully move away from single
16661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * segment elf objects. See the code in get_wr_offset (also #if'd 0)
16671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * that made this possible.
16681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     */
16691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if(wr_offset < 0xffffffff){
16701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        mprotect((void*) si->base, wr_offset, PROT_READ | PROT_EXEC);
16711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
16721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#else
16731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* TODO: Verify that this does the right thing in all cases, as it
16741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * presently probably does not. It is possible that an ELF image will
16751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * come with multiple read-only segments. What we ought to do is scan
16761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * the program headers again and mprotect all the read-only segments.
16771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * To prevent re-scanning the program header, we would have to build a
16781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * list of loadable segments in si, and then scan that instead. */
16791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (si->wrprotect_start != 0xffffffff && si->wrprotect_end != 0) {
16801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        mprotect((void *)si->wrprotect_start,
16811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                 si->wrprotect_end - si->wrprotect_start,
16821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                 PROT_READ | PROT_EXEC);
16831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
16841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
16851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
16861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* If this is a SET?ID program, dup /dev/null to opened stdin,
16871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project       stdout and stderr to close a security hole described in:
16881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
16891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    ftp://ftp.freebsd.org/pub/FreeBSD/CERT/advisories/FreeBSD-SA-02:23.stdio.asc
16901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
16911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     */
16921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (getuid() != geteuid() || getgid() != getegid())
16931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        nullify_closed_stdio ();
16941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    call_constructors(si);
16951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    notify_gdb_of_load(si);
16961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return 0;
16971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
16981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectfail:
16991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    ERROR("failed to link %s\n", si->name);
17001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->flags |= FLAG_ERROR;
17011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return -1;
17021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
17031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1704bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartleystatic void parse_library_path(char *path, char *delim)
1705bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley{
1706bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley    size_t len;
1707bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley    char *ldpaths_bufp = ldpaths_buf;
1708bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley    int i = 0;
1709bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley
1710bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley    len = strlcpy(ldpaths_buf, path, sizeof(ldpaths_buf));
1711bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley
1712bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley    while (i < LDPATH_MAX && (ldpaths[i] = strsep(&ldpaths_bufp, delim))) {
1713bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley        if (*ldpaths[i] != '\0')
1714bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley            ++i;
1715bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley    }
1716bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley
1717bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley    /* Forget the last path if we had to truncate; this occurs if the 2nd to
1718bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley     * last char isn't '\0' (i.e. not originally a delim). */
1719bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley    if (i > 0 && len >= sizeof(ldpaths_buf) &&
1720bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley            ldpaths_buf[sizeof(ldpaths_buf) - 2] != '\0') {
1721bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley        ldpaths[i - 1] = NULL;
1722bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley    } else {
1723bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley        ldpaths[i] = NULL;
1724bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley    }
1725bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley}
1726bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley
17271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint main(int argc, char **argv)
17281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
17291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return 0;
17301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
17311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
17321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define ANDROID_TLS_SLOTS  BIONIC_TLS_SLOTS
17331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
17341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic void * __tls_area[ANDROID_TLS_SLOTS];
17351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
17361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectunsigned __linker_init(unsigned **elfdata)
17371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
17381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    static soinfo linker_soinfo;
17391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
17401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    int argc = (int) *elfdata;
17411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    char **argv = (char**) (elfdata + 1);
17421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned *vecs = (unsigned*) (argv + argc + 1);
17431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    soinfo *si;
17441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    struct link_map * map;
1745bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley    char *ldpath_env = NULL;
17461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
17471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    pid = getpid();
17481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
17491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if TIMING
17501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    struct timeval t0, t1;
17511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    gettimeofday(&t0, 0);
17521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
17531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
17541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    __set_tls(__tls_area);
17551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    ((unsigned *)__get_tls())[TLS_SLOT_THREAD_ID] = gettid();
17561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
17571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    debugger_init();
17581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
17591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        /* skip past the environment */
17601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    while(vecs[0] != 0) {
17611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if(!strncmp((char*) vecs[0], "DEBUG=", 6)) {
17621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            debug_verbosity = atoi(((char*) vecs[0]) + 6);
1763bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley        } else if(!strncmp((char*) vecs[0], "LD_LIBRARY_PATH=", 16)) {
1764bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley            ldpath_env = (char*) vecs[0] + 16;
17651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
17661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        vecs++;
17671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
17681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    vecs++;
17691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
17701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    INFO("[ android linker & debugger ]\n");
17711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    DEBUG("%5d elfdata @ 0x%08x\n", pid, (unsigned)elfdata);
17721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
17731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si = alloc_info(argv[0]);
17741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if(si == 0) {
17751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        exit(-1);
17761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
17771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
17781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        /* bootstrap the link map, the main exe always needs to be first */
17791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->flags |= FLAG_EXE;
17801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    map = &(si->linkmap);
17811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
17821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    map->l_addr = 0;
17831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    map->l_name = argv[0];
17841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    map->l_prev = NULL;
17851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    map->l_next = NULL;
17861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
17871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    _r_debug.r_map = map;
17881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    r_debug_tail = map;
17891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
17901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        /* gdb expects the linker to be in the debug shared object list,
17911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project         * and we need to make sure that the reported load address is zero.
17921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project         * Without this, gdb gets the wrong idea of where rtld_db_dlactivity()
17931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project         * is.  Don't use alloc_info(), because the linker shouldn't
17941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project         * be on the soinfo list.
17951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project         */
17961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    strcpy((char*) linker_soinfo.name, "/system/bin/linker");
17971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    linker_soinfo.flags = 0;
17981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    linker_soinfo.base = 0;     // This is the important part; must be zero.
17991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    insert_soinfo_into_debug_map(&linker_soinfo);
18001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
18011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        /* extract information passed from the kernel */
18021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    while(vecs[0] != 0){
18031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        switch(vecs[0]){
18041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case AT_PHDR:
18051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->phdr = (Elf32_Phdr*) vecs[1];
18061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
18071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case AT_PHNUM:
18081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->phnum = (int) vecs[1];
18091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
18101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case AT_ENTRY:
18111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->entry = vecs[1];
18121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
18131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
18141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        vecs += 2;
18151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
18161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
18171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    ba_init();
18181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
18191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->base = 0;
18201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->dynamic = (unsigned *)-1;
18211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->wrprotect_start = 0xffffffff;
18221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->wrprotect_end = 0;
18231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1824bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley        /* Use LD_LIBRARY_PATH if we aren't setuid/setgid */
1825bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley    if (ldpath_env && getuid() == geteuid() && getgid() == getegid())
1826bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley        parse_library_path(ldpath_env, ":");
1827bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley
18282e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin    if(link_image(si, 0)) {
18292e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin        char errmsg[] = "CANNOT LINK EXECUTABLE\n";
18302e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin        write(2, __linker_dl_err_buf, strlen(__linker_dl_err_buf));
18312e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin        write(2, errmsg, sizeof(errmsg));
18321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        exit(-1);
18331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
18341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
18351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if TIMING
18361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    gettimeofday(&t1,NULL);
18371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    PRINT("LINKER TIME: %s: %d microseconds\n", argv[0], (int) (
18381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project               (((long long)t1.tv_sec * 1000000LL) + (long long)t1.tv_usec) -
18391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project               (((long long)t0.tv_sec * 1000000LL) + (long long)t0.tv_usec)
18401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project               ));
18411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
18421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if STATS
18431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    PRINT("RELO STATS: %s: %d abs, %d rel, %d copy, %d symbol\n", argv[0],
18441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project           linker_stats.reloc[RELOC_ABSOLUTE],
18451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project           linker_stats.reloc[RELOC_RELATIVE],
18461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project           linker_stats.reloc[RELOC_COPY],
18471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project           linker_stats.reloc[RELOC_SYMBOL]);
18481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
18491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if COUNT_PAGES
18501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    {
18511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        unsigned n;
18521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        unsigned i;
18531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        unsigned count = 0;
18541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        for(n = 0; n < 4096; n++){
18551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if(bitmask[n]){
18561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                unsigned x = bitmask[n];
18571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                for(i = 0; i < 8; i++){
18581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    if(x & 1) count++;
18591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    x >>= 1;
18601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                }
18611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
18621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
18631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        PRINT("PAGES MODIFIED: %s: %d (%dKB)\n", argv[0], count, count * 4);
18641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
18651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
18661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
18671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if TIMING || STATS || COUNT_PAGES
18681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    fflush(stdout);
18691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
18701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
18711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    TRACE("[ %5d Ready to execute '%s' @ 0x%08x ]\n", pid, si->name,
18721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project          si->entry);
18731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return si->entry;
18741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
1875