linker.cpp revision 4a9afcb10151b083cd2d75253385615f459172ed
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
544a9afcb10151b083cd2d75253385615f459172edIliyan Malchev#define ALLOW_SYMBOLS_FROM_MAIN 1
55ba52b3092f361580a5dea7ab8fbe2a227b55ee43James Dong#define SO_MAX 96
561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
57bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley/* Assume average path length of 64 and max 8 paths */
58bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley#define LDPATH_BUFSIZE 512
59bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley#define LDPATH_MAX 8
60bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley
611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* >>> IMPORTANT NOTE - READ ME BEFORE MODIFYING <<<
621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Do NOT use malloc() and friends or pthread_*() code here.
641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Don't use printf() either; it's caused mysterious memory
651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * corruption in the past.
661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * The linker runs before we bring up libc and it's easiest
671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * to make sure it does not depend on any complex libc features
681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * open issues / todo:
701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * - should we do anything special for STB_WEAK symbols?
721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * - are we doing everything we should for ARM_COPY relocations?
731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * - cleaner error reporting
741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * - after linking, set as much stuff as possible to READONLY
751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *   and NOEXEC
761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * - linker hardcodes PAGE_SIZE and PAGE_MASK because the kernel
771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *   headers provide versions that are negative...
781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * - allocate space for soinfo structs dynamically instead of
791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *   having a hard limit (64)
801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project*/
811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic int link_image(soinfo *si, unsigned wr_offset);
841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic int socount = 0;
861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic soinfo sopool[SO_MAX];
871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic soinfo *freelist = NULL;
881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic soinfo *solist = &libdl_info;
891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic soinfo *sonext = &libdl_info;
904a9afcb10151b083cd2d75253385615f459172edIliyan Malchev#if ALLOW_SYMBOLS_FROM_MAIN
914a9afcb10151b083cd2d75253385615f459172edIliyan Malchevstatic soinfo *somain; /* main process, always the one after libdl_info */
924a9afcb10151b083cd2d75253385615f459172edIliyan Malchev#endif
931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
946ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchevstatic inline int validate_soinfo(soinfo *si)
956ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev{
966ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev    return (si >= sopool && si < sopool + SO_MAX) ||
976ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev        si == &libdl_info;
986ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev}
996ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev
100bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartleystatic char ldpaths_buf[LDPATH_BUFSIZE];
101bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartleystatic const char *ldpaths[LDPATH_MAX + 1];
102bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley
1031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint debug_verbosity;
1041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic int pid;
1051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if STATS
1071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstruct _link_stats linker_stats;
1081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
1091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if COUNT_PAGES
1111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectunsigned bitmask[4096];
1121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
1131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#ifndef PT_ARM_EXIDX
1151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define PT_ARM_EXIDX    0x70000001      /* .ARM.exidx segment */
1161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
1171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1182e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin#define HOODLUM(name, ret, ...)                                               \
1192e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin    ret name __VA_ARGS__                                                      \
1202e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin    {                                                                         \
1212e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin        char errstr[] = "ERROR: " #name " called from the dynamic linker!\n"; \
1222e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin        write(2, errstr, sizeof(errstr));                                     \
1232e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin        abort();                                                              \
1242e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin    }
1252e85579c34047c305caf15fb0ebe02bf3d001d0eDima ZavinHOODLUM(malloc, void *, (size_t size));
1262e85579c34047c305caf15fb0ebe02bf3d001d0eDima ZavinHOODLUM(free, void, (void *ptr));
1272e85579c34047c305caf15fb0ebe02bf3d001d0eDima ZavinHOODLUM(realloc, void *, (void *ptr, size_t size));
1282e85579c34047c305caf15fb0ebe02bf3d001d0eDima ZavinHOODLUM(calloc, void *, (size_t cnt, size_t size));
1292e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin
1300353195f344666256dba474a15c9ba22cf0cccc9Dima Zavinstatic char tmp_err_buf[768];
1312e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavinstatic char __linker_dl_err_buf[768];
1322e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin#define DL_ERR(fmt, x...)                                                     \
1332e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin    do {                                                                      \
1342e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin        snprintf(__linker_dl_err_buf, sizeof(__linker_dl_err_buf),            \
1352e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin                 "%s[%d]: " fmt, __func__, __LINE__, ##x);                    \
136d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling        ERROR(fmt "\n", ##x);                                                      \
1372e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin    } while(0)
1382e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin
1392e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavinconst char *linker_get_error(void)
1402e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin{
1412e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin    return (const char *)&__linker_dl_err_buf[0];
1422e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin}
1432e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin
1441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/*
1451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * This function is an empty stub where GDB locates a breakpoint to get notified
1461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * about linker activity.
1471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
1481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectextern void __attribute__((noinline)) rtld_db_dlactivity(void);
1491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic struct r_debug _r_debug = {1, NULL, &rtld_db_dlactivity,
1511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                                  RT_CONSISTENT, 0};
1521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic struct link_map *r_debug_tail = 0;
1531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1545e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchevstatic pthread_mutex_t _r_debug_lock = PTHREAD_MUTEX_INITIALIZER;
1551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic void insert_soinfo_into_debug_map(soinfo * info)
1571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
1581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    struct link_map * map;
1591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* Copy the necessary fields into the debug structure.
1611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     */
1621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    map = &(info->linkmap);
1631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    map->l_addr = info->base;
1641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    map->l_name = (char*) info->name;
1651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* Stick the new library at the end of the list.
1671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * gdb tends to care more about libc than it does
1681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * about leaf libraries, and ordering it this way
1691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * reduces the back-and-forth over the wire.
1701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     */
1711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (r_debug_tail) {
1721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        r_debug_tail->l_next = map;
1731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        map->l_prev = r_debug_tail;
1741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        map->l_next = 0;
1751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    } else {
1761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        _r_debug.r_map = map;
1771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        map->l_prev = 0;
1781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        map->l_next = 0;
1791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
1801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    r_debug_tail = map;
1811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
1821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1835e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchevstatic void remove_soinfo_from_debug_map(soinfo * info)
1845e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev{
1855e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev    struct link_map * map = &(info->linkmap);
1865e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
1875e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev    if (r_debug_tail == map)
1885e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev        r_debug_tail = map->l_prev;
1895e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
1905e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev    if (map->l_prev) map->l_prev->l_next = map->l_next;
1915e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev    if (map->l_next) map->l_next->l_prev = map->l_prev;
1925e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev}
1935e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
1941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectvoid notify_gdb_of_load(soinfo * info)
1951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
1961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (info->flags & FLAG_EXE) {
1971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        // GDB already knows about the main executable
1981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return;
1991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
2001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2015e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev    pthread_mutex_lock(&_r_debug_lock);
2021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    _r_debug.r_state = RT_ADD;
2041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    rtld_db_dlactivity();
2051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    insert_soinfo_into_debug_map(info);
2071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    _r_debug.r_state = RT_CONSISTENT;
2091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    rtld_db_dlactivity();
2101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2115e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev    pthread_mutex_unlock(&_r_debug_lock);
2125e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev}
2135e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
2145e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchevvoid notify_gdb_of_unload(soinfo * info)
2155e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev{
2165e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev    if (info->flags & FLAG_EXE) {
2175e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev        // GDB already knows about the main executable
2185e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev        return;
2195e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev    }
2205e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
2215e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev    pthread_mutex_lock(&_r_debug_lock);
2225e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
2235e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev    _r_debug.r_state = RT_DELETE;
2245e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev    rtld_db_dlactivity();
2255e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
2265e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev    remove_soinfo_from_debug_map(info);
2275e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
2285e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev    _r_debug.r_state = RT_CONSISTENT;
2295e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev    rtld_db_dlactivity();
2305e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
2315e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev    pthread_mutex_unlock(&_r_debug_lock);
2321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
2331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectvoid notify_gdb_of_libraries()
2351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
2361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    _r_debug.r_state = RT_ADD;
2371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    rtld_db_dlactivity();
2381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    _r_debug.r_state = RT_CONSISTENT;
2391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    rtld_db_dlactivity();
2401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
2411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic soinfo *alloc_info(const char *name)
2431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
2441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    soinfo *si;
2451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if(strlen(name) >= SOINFO_NAME_LEN) {
247d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling        DL_ERR("%5d library name %s too long", pid, name);
2481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return 0;
2491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
2501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* The freelist is populated when we call free_info(), which in turn is
2521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project       done only by dlclose(), which is not likely to be used.
2531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    */
2541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (!freelist) {
2551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if(socount == SO_MAX) {
256d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling            DL_ERR("%5d too many libraries when loading %s", pid, name);
2571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return NULL;
2581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
2591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        freelist = sopool + socount++;
2601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        freelist->next = NULL;
2611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
2621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si = freelist;
2641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    freelist = freelist->next;
2651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* Make sure we get a clean block of soinfo */
2671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    memset(si, 0, sizeof(soinfo));
2681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    strcpy((char*) si->name, name);
2691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    sonext->next = si;
2701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->ba_index = -1; /* by default, prelinked */
2711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->next = NULL;
2721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->refcount = 0;
2731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    sonext = si;
2741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    TRACE("%5d name %s: allocated soinfo @ %p\n", pid, name, si);
2761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return si;
2771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
2781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic void free_info(soinfo *si)
2801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
2811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    soinfo *prev = NULL, *trav;
2821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    TRACE("%5d name %s: freeing soinfo @ %p\n", pid, si->name, si);
2841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for(trav = solist; trav != NULL; trav = trav->next){
2861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (trav == si)
2871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
2881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        prev = trav;
2891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
2901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (trav == NULL) {
2911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        /* si was not ni solist */
292d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling        DL_ERR("%5d name %s is not in solist!", pid, si->name);
2931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return;
2941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
2951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* prev will never be NULL, because the first entry in solist is
2971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project       always the static libdl_info.
2981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    */
2991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    prev->next = si->next;
3001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (si == sonext) sonext = prev;
3011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->next = freelist;
3021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    freelist = si;
3031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
3041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#ifndef LINKER_TEXT_BASE
3061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#error "linker's makefile must define LINKER_TEXT_BASE"
3071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
3081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#ifndef LINKER_AREA_SIZE
3091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#error "linker's makefile must define LINKER_AREA_SIZE"
3101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
3111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define LINKER_BASE ((LINKER_TEXT_BASE) & 0xfff00000)
3121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define LINKER_TOP  (LINKER_BASE + (LINKER_AREA_SIZE))
3131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectconst char *addr_to_name(unsigned addr)
3151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
3161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    soinfo *si;
3171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for(si = solist; si != 0; si = si->next){
3191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if((addr >= si->base) && (addr < (si->base + si->size))) {
3201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return si->name;
3211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
3221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
3231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if((addr >= LINKER_BASE) && (addr < LINKER_TOP)){
3251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return "linker";
3261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
3271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return "";
3291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
3301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* For a given PC, find the .so that it belongs to.
3321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Returns the base address of the .ARM.exidx section
3331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * for that .so, and the number of 8-byte entries
3341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * in that section (via *pcount).
3351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
3361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Intended to be called by libc's __gnu_Unwind_Find_exidx().
3371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
3381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * This function is exposed via dlfcn.c and libdl.so.
3391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
3401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#ifdef ANDROID_ARM_LINKER
3411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project_Unwind_Ptr dl_unwind_find_exidx(_Unwind_Ptr pc, int *pcount)
3421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
3431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    soinfo *si;
3441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned addr = (unsigned)pc;
3451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if ((addr < LINKER_BASE) || (addr >= LINKER_TOP)) {
3471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        for (si = solist; si != 0; si = si->next){
3481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if ((addr >= si->base) && (addr < (si->base + si->size))) {
3491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                *pcount = si->ARM_exidx_count;
3501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                return (_Unwind_Ptr)(si->base + (unsigned long)si->ARM_exidx);
3511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
3521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
3531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
3541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project   *pcount = 0;
3551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return NULL;
3561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
3571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#elif defined(ANDROID_X86_LINKER)
3581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* Here, we only have to provide a callback to iterate across all the
3591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * loaded libraries. gcc_eh does the rest. */
3601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint
3611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectdl_iterate_phdr(int (*cb)(struct dl_phdr_info *info, size_t size, void *data),
3621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                void *data)
3631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
3641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    soinfo *si;
3651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    struct dl_phdr_info dl_info;
3661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    int rv = 0;
3671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for (si = solist; si != NULL; si = si->next) {
3691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        dl_info.dlpi_addr = si->linkmap.l_addr;
3701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        dl_info.dlpi_name = si->linkmap.l_name;
3711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        dl_info.dlpi_phdr = si->phdr;
3721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        dl_info.dlpi_phnum = si->phnum;
3731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        rv = cb(&dl_info, sizeof (struct dl_phdr_info), data);
3741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (rv != 0)
3751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
3761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
3771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return rv;
3781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
3791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
3801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic Elf32_Sym *_elf_lookup(soinfo *si, unsigned hash, const char *name)
3821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
3831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Sym *s;
3841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Sym *symtab = si->symtab;
3851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    const char *strtab = si->strtab;
3861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned n;
3871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    TRACE_TYPE(LOOKUP, "%5d SEARCH %s in %s@0x%08x %08x %d\n", pid,
3891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project               name, si->name, si->base, hash, hash % si->nbucket);
3901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    n = hash % si->nbucket;
3911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for(n = si->bucket[hash % si->nbucket]; n != 0; n = si->chain[n]){
3931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        s = symtab + n;
3941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if(strcmp(strtab + s->st_name, name)) continue;
3951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            /* only concern ourselves with global symbols */
3971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        switch(ELF32_ST_BIND(s->st_info)){
3981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case STB_GLOBAL:
3991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                /* no section == undefined */
4001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if(s->st_shndx == 0) continue;
4011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
4021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case STB_WEAK:
4031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            TRACE_TYPE(LOOKUP, "%5d FOUND %s in %s (%08x) %d\n", pid,
4041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                       name, si->name, s->st_value, s->st_size);
4051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return s;
4061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
4071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
4081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
4091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return 0;
4101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
4111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
4121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic unsigned elfhash(const char *_name)
4131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
4141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    const unsigned char *name = (const unsigned char *) _name;
4151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned h = 0, g;
4161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
4171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    while(*name) {
4181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        h = (h << 4) + *name++;
4191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        g = h & 0xf0000000;
4201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        h ^= g;
4211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        h ^= g >> 24;
4221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
4231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return h;
4241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
4251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
4261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic Elf32_Sym *
4271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project_do_lookup_in_so(soinfo *si, const char *name, unsigned *elf_hash)
4281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
4291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (*elf_hash == 0)
4301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        *elf_hash = elfhash(name);
4311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return _elf_lookup (si, *elf_hash, name);
4321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
4331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
4346ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchevstatic Elf32_Sym *
4356ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev_do_lookup(soinfo *si, const char *name, unsigned *base)
4366ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev{
4376ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev    unsigned elf_hash = 0;
4386ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev    Elf32_Sym *s;
4396ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev    unsigned *d;
4406ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev    soinfo *lsi = si;
4416ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev
4426ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev    /* Look for symbols in the local scope first (the object who is
4436ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev     * searching). This happens with C++ templates on i386 for some
4446ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev     * reason. */
4456ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev    s = _do_lookup_in_so(si, name, &elf_hash);
4466ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev    if(s != NULL)
4476ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev        goto done;
4486ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev
4496ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev    for(d = si->dynamic; *d; d += 2) {
4506ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev        if(d[0] == DT_NEEDED){
4516ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev            lsi = (soinfo *)d[1];
4526ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev            if (!validate_soinfo(lsi)) {
4536ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev                DL_ERR("%5d bad DT_NEEDED pointer in %s",
4546ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev                       pid, si->name);
4556ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev                return 0;
4566ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev            }
4576ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev
4586ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev            DEBUG("%5d %s: looking up %s in %s\n",
4596ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev                  pid, si->name, name, lsi->name);
4606ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev            s = _do_lookup_in_so(lsi, name, &elf_hash);
4616ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev            if(s != NULL)
4626ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev                goto done;
4636ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev        }
4646ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev    }
4656ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev
4664a9afcb10151b083cd2d75253385615f459172edIliyan Malchev#if ALLOW_SYMBOLS_FROM_MAIN
4674a9afcb10151b083cd2d75253385615f459172edIliyan Malchev    /* If we are resolving relocations while dlopen()ing a library, it's OK for
4684a9afcb10151b083cd2d75253385615f459172edIliyan Malchev     * the library to resolve a symbol that's defined in the executable itself,
4694a9afcb10151b083cd2d75253385615f459172edIliyan Malchev     * although this is rare and is generally a bad idea.
4704a9afcb10151b083cd2d75253385615f459172edIliyan Malchev     */
4714a9afcb10151b083cd2d75253385615f459172edIliyan Malchev    if (somain) {
4724a9afcb10151b083cd2d75253385615f459172edIliyan Malchev        lsi = somain;
4734a9afcb10151b083cd2d75253385615f459172edIliyan Malchev        DEBUG("%5d %s: looking up %s in executable %s\n",
4744a9afcb10151b083cd2d75253385615f459172edIliyan Malchev              pid, si->name, name, lsi->name);
4754a9afcb10151b083cd2d75253385615f459172edIliyan Malchev        s = _do_lookup_in_so(lsi, name, &elf_hash);
4764a9afcb10151b083cd2d75253385615f459172edIliyan Malchev    }
4774a9afcb10151b083cd2d75253385615f459172edIliyan Malchev#endif
4784a9afcb10151b083cd2d75253385615f459172edIliyan Malchev
4796ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchevdone:
4806ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev    if(s != NULL) {
4816ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev        TRACE_TYPE(LOOKUP, "%5d si %s sym %s s->st_value = 0x%08x, "
4826ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev                   "found in %s, base = 0x%08x\n",
4836ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev                   pid, si->name, name, s->st_value, lsi->name, lsi->base);
4846ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev        *base = lsi->base;
4856ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev        return s;
4866ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev    }
4876ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev
4886ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev    return 0;
4896ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev}
4906ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev
4916ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev/* This is used by dl_sym().  It performs symbol lookup only within the
4926ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev   specified soinfo object and not in any of its dependencies.
4936ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev */
4941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source ProjectElf32_Sym *lookup_in_library(soinfo *si, const char *name)
4951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
4961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned unused = 0;
4971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return _do_lookup_in_so(si, name, &unused);
4981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
4991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5006ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev/* This is used by dl_sym().  It performs a global symbol lookup.
5016ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev */
5029ea64da6c511e8f9f4edae4c10c20879957631abIliyan MalchevElf32_Sym *lookup(const char *name, soinfo **found)
5031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
5041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned elf_hash = 0;
5051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Sym *s = NULL;
5061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    soinfo *si;
5071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for(si = solist; (s == NULL) && (si != NULL); si = si->next)
5091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    {
5106ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev        if(si->flags & FLAG_ERROR)
5111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            continue;
5121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        s = _do_lookup_in_so(si, name, &elf_hash);
5131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (s != NULL) {
5149ea64da6c511e8f9f4edae4c10c20879957631abIliyan Malchev            *found = si;
5151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
5161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
5171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
5181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5196ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev    if(s != NULL) {
5201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE_TYPE(LOOKUP, "%5d %s s->st_value = 0x%08x, "
5211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                   "si->base = 0x%08x\n", pid, name, s->st_value, si->base);
5221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return s;
5231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
5241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return 0;
5261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
5271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if 0
5291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic void dump(soinfo *si)
5301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
5311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Sym *s = si->symtab;
5321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned n;
5331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for(n = 0; n < si->nchain; n++) {
5351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("%5d %04d> %08x: %02x %04x %08x %08x %s\n", pid, n, s,
5361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project               s->st_info, s->st_shndx, s->st_value, s->st_size,
5371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project               si->strtab + s->st_name);
5381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        s++;
5391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
5401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
5411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
5421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic const char *sopaths[] = {
5441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    "/system/lib",
5451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    "/lib",
5461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    0
5471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project};
5481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic int _open_lib(const char *name)
5501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
5511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    int fd;
5521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    struct stat filestat;
5531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if ((stat(name, &filestat) >= 0) && S_ISREG(filestat.st_mode)) {
5551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if ((fd = open(name, O_RDONLY)) >= 0)
5561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return fd;
5571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
5581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return -1;
5601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
5611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic int open_library(const char *name)
5631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
5641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    int fd;
5651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    char buf[512];
5661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    const char **path;
567bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley    int n;
5681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    TRACE("[ %5d opening %s ]\n", pid, name);
5701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if(name == 0) return -1;
5721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if(strlen(name) > 256) return -1;
5731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if ((name[0] == '/') && ((fd = _open_lib(name)) >= 0))
5751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return fd;
5761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
577bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley    for (path = ldpaths; *path; path++) {
578bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley        n = snprintf(buf, sizeof(buf), "%s/%s", *path, name);
579bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley        if (n < 0 || n >= (int)sizeof(buf)) {
580bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley            WARN("Ignoring very long library path: %s/%s\n", *path, name);
581bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley            continue;
582bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley        }
583bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley        if ((fd = _open_lib(buf)) >= 0)
584bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley            return fd;
585bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley    }
5861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for (path = sopaths; *path; path++) {
587bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley        n = snprintf(buf, sizeof(buf), "%s/%s", *path, name);
588bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley        if (n < 0 || n >= (int)sizeof(buf)) {
589bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley            WARN("Ignoring very long library path: %s/%s\n", *path, name);
590bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley            continue;
591bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley        }
5921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if ((fd = _open_lib(buf)) >= 0)
5931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return fd;
5941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
5951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return -1;
5971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
5981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* temporary space for holding the first page of the shared lib
6001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * which contains the elf header (with the pht). */
6011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic unsigned char __header[PAGE_SIZE];
6021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projecttypedef struct {
6041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    long mmap_addr;
6051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    char tag[4]; /* 'P', 'R', 'E', ' ' */
6061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} prelink_info_t;
6071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* Returns the requested base address if the library is prelinked,
6091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * and 0 otherwise.  */
6101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic unsigned long
6111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectis_prelinked(int fd, const char *name)
6121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
6131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    off_t sz;
6141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    prelink_info_t info;
6151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    sz = lseek(fd, -sizeof(prelink_info_t), SEEK_END);
6171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (sz < 0) {
618d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling        DL_ERR("lseek() failed!");
6191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return 0;
6201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
6211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (read(fd, &info, sizeof(info)) != sizeof(info)) {
6231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        WARN("Could not read prelink_info_t structure for `%s`\n", name);
6241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return 0;
6251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
6261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (strncmp(info.tag, "PRE ", 4)) {
6281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        WARN("`%s` is not a prelinked library\n", name);
6291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return 0;
6301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
6311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return (unsigned long)info.mmap_addr;
6331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
6341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* verify_elf_object
6361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *      Verifies if the object @ base is a valid ELF object
6371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
6381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Args:
6391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
6401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Returns:
6411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *       0 on success
6421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *      -1 if no valid ELF object is found @ base.
6431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
6441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic int
6451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectverify_elf_object(void *base, const char *name)
6461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
6471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Ehdr *hdr = (Elf32_Ehdr *) base;
6481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (hdr->e_ident[EI_MAG0] != ELFMAG0) return -1;
6501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (hdr->e_ident[EI_MAG1] != ELFMAG1) return -1;
6511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (hdr->e_ident[EI_MAG2] != ELFMAG2) return -1;
6521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (hdr->e_ident[EI_MAG3] != ELFMAG3) return -1;
6531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* TODO: Should we verify anything else in the header? */
6551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return 0;
6571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
6581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* get_lib_extents
6611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *      Retrieves the base (*base) address where the ELF object should be
6621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *      mapped and its overall memory size (*total_sz).
6631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
6641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Args:
6651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *      fd: Opened file descriptor for the library
6661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *      name: The name of the library
6671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *      _hdr: Pointer to the header page of the library
6681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *      total_sz: Total size of the memory that should be allocated for
6691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *                this library
6701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
6711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Returns:
6721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *      -1 if there was an error while trying to get the lib extents.
6731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *         The possible reasons are:
6741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *             - Could not determine if the library was prelinked.
6751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *             - The library provided is not a valid ELF object
6761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *       0 if the library did not request a specific base offset (normal
6771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *         for non-prelinked libs)
6781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     > 0 if the library requests a specific address to be mapped to.
6791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *         This indicates a pre-linked library.
6801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
6811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic unsigned
6821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectget_lib_extents(int fd, const char *name, void *__hdr, unsigned *total_sz)
6831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
6841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned req_base;
6851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned min_vaddr = 0xffffffff;
6861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned max_vaddr = 0;
6871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned char *_hdr = (unsigned char *)__hdr;
6881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Ehdr *ehdr = (Elf32_Ehdr *)_hdr;
6891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Phdr *phdr;
6901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    int cnt;
6911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    TRACE("[ %5d Computing extents for '%s'. ]\n", pid, name);
6931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (verify_elf_object(_hdr, name) < 0) {
694d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling        DL_ERR("%5d - %s is not a valid ELF object", pid, name);
6951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return (unsigned)-1;
6961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
6971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    req_base = (unsigned) is_prelinked(fd, name);
6991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (req_base == (unsigned)-1)
7001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return -1;
7011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    else if (req_base != 0) {
7021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d - Prelinked library '%s' requesting base @ 0x%08x ]\n",
7031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              pid, name, req_base);
7041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    } else {
7051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d - Non-prelinked library '%s' found. ]\n", pid, name);
7061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
7071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
7081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    phdr = (Elf32_Phdr *)(_hdr + ehdr->e_phoff);
7091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
7101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* find the min/max p_vaddrs from all the PT_LOAD segments so we can
7111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * get the range. */
7121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for (cnt = 0; cnt < ehdr->e_phnum; ++cnt, ++phdr) {
7131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (phdr->p_type == PT_LOAD) {
7141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if ((phdr->p_vaddr + phdr->p_memsz) > max_vaddr)
7151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                max_vaddr = phdr->p_vaddr + phdr->p_memsz;
7161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if (phdr->p_vaddr < min_vaddr)
7171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                min_vaddr = phdr->p_vaddr;
7181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
7191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
7201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
7211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if ((min_vaddr == 0xffffffff) && (max_vaddr == 0)) {
722d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling        DL_ERR("%5d - No loadable segments found in %s.", pid, name);
7231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return (unsigned)-1;
7241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
7251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
7261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* truncate min_vaddr down to page boundary */
7271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    min_vaddr &= ~PAGE_MASK;
7281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
7291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* round max_vaddr up to the next page */
7301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    max_vaddr = (max_vaddr + PAGE_SIZE - 1) & ~PAGE_MASK;
7311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
7321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    *total_sz = (max_vaddr - min_vaddr);
7331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return (unsigned)req_base;
7341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
7351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
7361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* alloc_mem_region
7371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
7381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     This function reserves a chunk of memory to be used for mapping in
7391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     the shared library. We reserve the entire memory region here, and
7401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     then the rest of the linker will relocate the individual loadable
7411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     segments into the correct locations within this memory range.
7421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
7431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Args:
7441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     si->base: The requested base of the allocation. If 0, a sane one will be
7451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *               chosen in the range LIBBASE <= base < LIBLAST.
7461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     si->size: The size of the allocation.
7471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
7481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Returns:
7491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     -1 on failure, and 0 on success.  On success, si->base will contain
7501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     the virtual address at which the library will be mapped.
7511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
7521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
7531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic int reserve_mem_region(soinfo *si)
7541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
7551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    void *base = mmap((void *)si->base, si->size, PROT_READ | PROT_EXEC,
7561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                      MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
7571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (base == MAP_FAILED) {
7582e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin        DL_ERR("%5d can NOT map (%sprelinked) library '%s' at 0x%08x "
759d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling              "as requested, will try general pool: %d (%s)",
7601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              pid, (si->base ? "" : "non-"), si->name, si->base,
7611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              errno, strerror(errno));
7621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return -1;
7631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    } else if (base != (void *)si->base) {
7642e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin        DL_ERR("OOPS: %5d %sprelinked library '%s' mapped at 0x%08x, "
765d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling              "not at 0x%08x", pid, (si->base ? "" : "non-"),
7661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              si->name, (unsigned)base, si->base);
7671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        munmap(base, si->size);
7681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return -1;
7691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
7701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return 0;
7711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
7721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
7731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic int
7741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectalloc_mem_region(soinfo *si)
7751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
7761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (si->base) {
7771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        /* Attempt to mmap a prelinked library. */
7781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        si->ba_index = -1;
7791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return reserve_mem_region(si);
7801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
7811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
7821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* This is not a prelinked library, so we attempt to allocate space
7831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project       for it from the buddy allocator, which manages the area between
7841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project       LIBBASE and LIBLAST.
7851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    */
7861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->ba_index = ba_allocate(si->size);
7871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if(si->ba_index >= 0) {
7881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        si->base = ba_start_addr(si->ba_index);
7891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        PRINT("%5d mapping library '%s' at %08x (index %d) " \
7901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              "through buddy allocator.\n",
7911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              pid, si->name, si->base, si->ba_index);
7921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (reserve_mem_region(si) < 0) {
7931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            ba_free(si->ba_index);
7941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->ba_index = -1;
7951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->base = 0;
7961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            goto err;
7971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
7981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return 0;
7991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
8001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
8011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projecterr:
802d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling    DL_ERR("OOPS: %5d cannot map library '%s'. no vspace available.",
8031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project          pid, si->name);
8041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return -1;
8051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
8061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
8071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define MAYBE_MAP_FLAG(x,from,to)    (((x) & (from)) ? (to) : 0)
8081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define PFLAGS_TO_PROT(x)            (MAYBE_MAP_FLAG((x), PF_X, PROT_EXEC) | \
8091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                                      MAYBE_MAP_FLAG((x), PF_R, PROT_READ) | \
8101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                                      MAYBE_MAP_FLAG((x), PF_W, PROT_WRITE))
8111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* load_segments
8121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
8131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     This function loads all the loadable (PT_LOAD) segments into memory
8141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     at their appropriate memory offsets off the base address.
8151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
8161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Args:
8171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     fd: Open file descriptor to the library to load.
8181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     header: Pointer to a header page that contains the ELF header.
8191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *             This is needed since we haven't mapped in the real file yet.
8201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     si: ptr to soinfo struct describing the shared object.
8211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
8221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Returns:
8231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     0 on success, -1 on failure.
8241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
8251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic int
8261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectload_segments(int fd, void *header, soinfo *si)
8271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
8281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Ehdr *ehdr = (Elf32_Ehdr *)header;
8291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Phdr *phdr = (Elf32_Phdr *)((unsigned char *)header + ehdr->e_phoff);
8301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned char *base = (unsigned char *)si->base;
8311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    int cnt;
8321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned len;
8331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned char *tmp;
8341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned char *pbase;
8351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned char *extra_base;
8361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned extra_len;
8371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned total_sz = 0;
8381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
8391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->wrprotect_start = 0xffffffff;
8401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->wrprotect_end = 0;
8411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
8421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    TRACE("[ %5d - Begin loading segments for '%s' @ 0x%08x ]\n",
8431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project          pid, si->name, (unsigned)si->base);
8441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* Now go through all the PT_LOAD segments and map them into memory
8451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * at the appropriate locations. */
8461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for (cnt = 0; cnt < ehdr->e_phnum; ++cnt, ++phdr) {
8471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (phdr->p_type == PT_LOAD) {
8481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            DEBUG_DUMP_PHDR(phdr, "PT_LOAD", pid);
8491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            /* we want to map in the segment on a page boundary */
8501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            tmp = base + (phdr->p_vaddr & (~PAGE_MASK));
8511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            /* add the # of bytes we masked off above to the total length. */
8521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            len = phdr->p_filesz + (phdr->p_vaddr & PAGE_MASK);
8531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
8541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            TRACE("[ %d - Trying to load segment from '%s' @ 0x%08x "
8551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                  "(0x%08x). p_vaddr=0x%08x p_offset=0x%08x ]\n", pid, si->name,
8561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                  (unsigned)tmp, len, phdr->p_vaddr, phdr->p_offset);
8571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            pbase = mmap(tmp, len, PFLAGS_TO_PROT(phdr->p_flags),
8581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                         MAP_PRIVATE | MAP_FIXED, fd,
8591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                         phdr->p_offset & (~PAGE_MASK));
8601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if (pbase == MAP_FAILED) {
8612e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin                DL_ERR("%d failed to map segment from '%s' @ 0x%08x (0x%08x). "
862d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling                      "p_vaddr=0x%08x p_offset=0x%08x", pid, si->name,
8631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                      (unsigned)tmp, len, phdr->p_vaddr, phdr->p_offset);
8641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                goto fail;
8651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
8661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
8671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            /* If 'len' didn't end on page boundary, and it's a writable
8681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             * segment, zero-fill the rest. */
8691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if ((len & PAGE_MASK) && (phdr->p_flags & PF_W))
8701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                memset((void *)(pbase + len), 0, PAGE_SIZE - (len & PAGE_MASK));
8711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
8721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            /* Check to see if we need to extend the map for this segment to
8731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             * cover the diff between filesz and memsz (i.e. for bss).
8741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *
8751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *  base           _+---------------------+  page boundary
8761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *                  .                     .
8771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *                  |                     |
8781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *                  .                     .
8791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *  pbase          _+---------------------+  page boundary
8801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *                  |                     |
8811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *                  .                     .
8821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *  base + p_vaddr _|                     |
8831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *                  . \          \        .
8841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *                  . | filesz   |        .
8851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *  pbase + len    _| /          |        |
8861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *     <0 pad>      .            .        .
8871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *  extra_base     _+------------|--------+  page boundary
8881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *               /  .            .        .
8891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *               |  .            .        .
8901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *               |  +------------|--------+  page boundary
8911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *  extra_len->  |  |            |        |
8921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *               |  .            | memsz  .
8931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *               |  .            |        .
8941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *               \ _|            /        |
8951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *                  .                     .
8961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *                  |                     |
8971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *                 _+---------------------+  page boundary
8981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             */
8991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            tmp = (unsigned char *)(((unsigned)pbase + len + PAGE_SIZE - 1) &
9001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                                    (~PAGE_MASK));
9011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if (tmp < (base + phdr->p_vaddr + phdr->p_memsz)) {
9021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                extra_len = base + phdr->p_vaddr + phdr->p_memsz - tmp;
9031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                TRACE("[ %5d - Need to extend segment from '%s' @ 0x%08x "
9041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                      "(0x%08x) ]\n", pid, si->name, (unsigned)tmp, extra_len);
9051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                /* map in the extra page(s) as anonymous into the range.
9061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                 * This is probably not necessary as we already mapped in
9071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                 * the entire region previously, but we just want to be
9081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                 * sure. This will also set the right flags on the region
9091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                 * (though we can probably accomplish the same thing with
9101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                 * mprotect).
9111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                 */
9121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                extra_base = mmap((void *)tmp, extra_len,
9131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                                  PFLAGS_TO_PROT(phdr->p_flags),
9141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                                  MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS,
9151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                                  -1, 0);
9161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                if (extra_base == MAP_FAILED) {
9172e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin                    DL_ERR("[ %5d - failed to extend segment from '%s' @ 0x%08x"
918d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling                           " (0x%08x) ]", pid, si->name, (unsigned)tmp,
9191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                          extra_len);
9201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    goto fail;
9211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                }
9221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                /* TODO: Check if we need to memset-0 this region.
9231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                 * Anonymous mappings are zero-filled copy-on-writes, so we
9241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                 * shouldn't need to. */
9251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                TRACE("[ %5d - Segment from '%s' extended @ 0x%08x "
9261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                      "(0x%08x)\n", pid, si->name, (unsigned)extra_base,
9271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                      extra_len);
9281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
9291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            /* set the len here to show the full extent of the segment we
9301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             * just loaded, mostly for debugging */
9311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            len = (((unsigned)base + phdr->p_vaddr + phdr->p_memsz +
9321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    PAGE_SIZE - 1) & (~PAGE_MASK)) - (unsigned)pbase;
9331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            TRACE("[ %5d - Successfully loaded segment from '%s' @ 0x%08x "
9341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                  "(0x%08x). p_vaddr=0x%08x p_offset=0x%08x\n", pid, si->name,
9351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                  (unsigned)pbase, len, phdr->p_vaddr, phdr->p_offset);
9361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            total_sz += len;
9371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            /* Make the section writable just in case we'll have to write to
9381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             * it during relocation (i.e. text segment). However, we will
9391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             * remember what range of addresses should be write protected.
9401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *
9411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             */
9421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if (!(phdr->p_flags & PF_W)) {
9431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                if ((unsigned)pbase < si->wrprotect_start)
9441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    si->wrprotect_start = (unsigned)pbase;
9451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                if (((unsigned)pbase + len) > si->wrprotect_end)
9461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    si->wrprotect_end = (unsigned)pbase + len;
9471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                mprotect(pbase, len,
9481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                         PFLAGS_TO_PROT(phdr->p_flags) | PROT_WRITE);
9491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
9501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        } else if (phdr->p_type == PT_DYNAMIC) {
9511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            DEBUG_DUMP_PHDR(phdr, "PT_DYNAMIC", pid);
9521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            /* this segment contains the dynamic linking information */
9531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->dynamic = (unsigned *)(base + phdr->p_vaddr);
9541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        } else {
9551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#ifdef ANDROID_ARM_LINKER
9561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if (phdr->p_type == PT_ARM_EXIDX) {
9571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                DEBUG_DUMP_PHDR(phdr, "PT_ARM_EXIDX", pid);
9581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                /* exidx entries (used for stack unwinding) are 8 bytes each.
9591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                 */
9601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                si->ARM_exidx = (unsigned *)phdr->p_vaddr;
9611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                si->ARM_exidx_count = phdr->p_memsz / 8;
9621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
9631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
9641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
9651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
9661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
9671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
9681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* Sanity check */
9691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (total_sz > si->size) {
9702e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin        DL_ERR("%5d - Total length (0x%08x) of mapped segments from '%s' is "
971d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling              "greater than what was allocated (0x%08x). THIS IS BAD!",
9721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              pid, total_sz, si->name, si->size);
9731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        goto fail;
9741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
9751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
9761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    TRACE("[ %5d - Finish loading segments for '%s' @ 0x%08x. "
9771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project          "Total memory footprint: 0x%08x bytes ]\n", pid, si->name,
9781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project          (unsigned)si->base, si->size);
9791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return 0;
9801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
9811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectfail:
9821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* We can just blindly unmap the entire region even though some things
9831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * were mapped in originally with anonymous and others could have been
9841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * been mapped in from the file before we failed. The kernel will unmap
9851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * all the pages in the range, irrespective of how they got there.
9861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     */
9871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    munmap((void *)si->base, si->size);
9881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->flags |= FLAG_ERROR;
9891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return -1;
9901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
9911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
9921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* TODO: Implement this to take care of the fact that Android ARM
9931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * ELF objects shove everything into a single loadable segment that has the
9941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * write bit set. wr_offset is then used to set non-(data|bss) pages to be
9951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * non-writable.
9961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
9971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if 0
9981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic unsigned
9991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectget_wr_offset(int fd, const char *name, Elf32_Ehdr *ehdr)
10001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
10011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Shdr *shdr_start;
10021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Shdr *shdr;
10031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    int shdr_sz = ehdr->e_shnum * sizeof(Elf32_Shdr);
10041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    int cnt;
10051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned wr_offset = 0xffffffff;
10061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    shdr_start = mmap(0, shdr_sz, PROT_READ, MAP_PRIVATE, fd,
10081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                      ehdr->e_shoff & (~PAGE_MASK));
10091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (shdr_start == MAP_FAILED) {
10101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        WARN("%5d - Could not read section header info from '%s'. Will not "
10111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             "not be able to determine write-protect offset.\n", pid, name);
10121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return (unsigned)-1;
10131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
10141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for(cnt = 0, shdr = shdr_start; cnt < ehdr->e_shnum; ++cnt, ++shdr) {
10161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if ((shdr->sh_type != SHT_NULL) && (shdr->sh_flags & SHF_WRITE) &&
10171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            (shdr->sh_addr < wr_offset)) {
10181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            wr_offset = shdr->sh_addr;
10191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
10201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
10211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    munmap(shdr_start, shdr_sz);
10231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return wr_offset;
10241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
10251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
10261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic soinfo *
10281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectload_library(const char *name)
10291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
10301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    int fd = open_library(name);
10311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    int cnt;
10321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned ext_sz;
10331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned req_base;
1034fde8642fc43bdd224e43e5ee9583a49a758fb03cErik Gilling    const char *bname;
10351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    soinfo *si = NULL;
10361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Ehdr *hdr;
10371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10382e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin    if(fd == -1) {
1039d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling        DL_ERR("Library '%s' not found", name);
10401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return NULL;
10412e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin    }
10421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* We have to read the ELF header to figure out what to do with this image
10441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     */
10451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (lseek(fd, 0, SEEK_SET) < 0) {
1046d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling        DL_ERR("lseek() failed!");
10471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        goto fail;
10481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
10491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if ((cnt = read(fd, &__header[0], PAGE_SIZE)) < 0) {
1051d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling        DL_ERR("read() failed!");
10521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        goto fail;
10531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
10541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* Parse the ELF header and get the size of the memory footprint for
10561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * the library */
10571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    req_base = get_lib_extents(fd, name, &__header[0], &ext_sz);
10581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (req_base == (unsigned)-1)
10591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        goto fail;
10601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    TRACE("[ %5d - '%s' (%s) wants base=0x%08x sz=0x%08x ]\n", pid, name,
10611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project          (req_base ? "prelinked" : "not pre-linked"), req_base, ext_sz);
10621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* Now configure the soinfo struct where we'll store all of our data
10641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * for the ELF object. If the loading fails, we waste the entry, but
10651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * same thing would happen if we failed during linking. Configuring the
10661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * soinfo struct here is a lot more convenient.
10671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     */
1068fde8642fc43bdd224e43e5ee9583a49a758fb03cErik Gilling    bname = strrchr(name, '/');
1069fde8642fc43bdd224e43e5ee9583a49a758fb03cErik Gilling    si = alloc_info(bname ? bname + 1 : name);
10701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (si == NULL)
10711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        goto fail;
10721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* Carve out a chunk of memory where we will map in the individual
10741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * segments */
10751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->base = req_base;
10761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->size = ext_sz;
10771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->flags = 0;
10781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->entry = 0;
10791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->dynamic = (unsigned *)-1;
10801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (alloc_mem_region(si) < 0)
10811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        goto fail;
10821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    TRACE("[ %5d allocated memory for %s @ %p (0x%08x) ]\n",
10841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project          pid, name, (void *)si->base, (unsigned) ext_sz);
10851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* Now actually load the library's segments into right places in memory */
10871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (load_segments(fd, &__header[0], si) < 0) {
10881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (si->ba_index >= 0) {
10891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            ba_free(si->ba_index);
10901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->ba_index = -1;
10911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
10921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        goto fail;
10931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
10941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* this might not be right. Technically, we don't even need this info
10961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * once we go through 'load_segments'. */
10971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    hdr = (Elf32_Ehdr *)si->base;
10981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->phdr = (Elf32_Phdr *)((unsigned char *)si->base + hdr->e_phoff);
10991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->phnum = hdr->e_phnum;
11001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /**/
11011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
11021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    close(fd);
11031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return si;
11041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
11051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectfail:
11061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (si) free_info(si);
11071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    close(fd);
11081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return NULL;
11091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
11101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
11111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic soinfo *
11121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectinit_library(soinfo *si)
11131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
11141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned wr_offset = 0xffffffff;
11151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
11161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* At this point we know that whatever is loaded @ base is a valid ELF
11171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * shared library whose segments are properly mapped in. */
11181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    TRACE("[ %5d init_library base=0x%08x sz=0x%08x name='%s') ]\n",
11191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project          pid, si->base, si->size, si->name);
11201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
11211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (si->base < LIBBASE || si->base >= LIBLAST)
11221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        si->flags |= FLAG_PRELINKED;
11231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
11241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if(link_image(si, wr_offset)) {
11251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            /* We failed to link.  However, we can only restore libbase
11261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            ** if no additional libraries have moved it since we updated it.
11271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            */
11281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        munmap((void *)si->base, si->size);
11291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return NULL;
11301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
11311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
11321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return si;
11331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
11341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
11351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectsoinfo *find_library(const char *name)
11361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
11371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    soinfo *si;
1138fde8642fc43bdd224e43e5ee9583a49a758fb03cErik Gilling    const char *bname = strrchr(name, '/');
1139fde8642fc43bdd224e43e5ee9583a49a758fb03cErik Gilling    bname = bname ? bname + 1 : name;
11401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
11411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for(si = solist; si != 0; si = si->next){
1142fde8642fc43bdd224e43e5ee9583a49a758fb03cErik Gilling        if(!strcmp(bname, si->name)) {
114330eb40241c612a7ddbd21c4daa4e7bbfd9d5e89fErik Gilling            if(si->flags & FLAG_ERROR) {
114430eb40241c612a7ddbd21c4daa4e7bbfd9d5e89fErik Gilling                DL_ERR("%5d '%s' failed to load previously", pid, bname);
114530eb40241c612a7ddbd21c4daa4e7bbfd9d5e89fErik Gilling                return NULL;
114630eb40241c612a7ddbd21c4daa4e7bbfd9d5e89fErik Gilling            }
11471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if(si->flags & FLAG_LINKED) return si;
1148d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling            DL_ERR("OOPS: %5d recursive link to '%s'", pid, si->name);
11492e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin            return NULL;
11501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
11511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
11521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
11531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    TRACE("[ %5d '%s' has not been loaded yet.  Locating...]\n", pid, name);
11541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si = load_library(name);
11551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if(si == NULL)
11561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return NULL;
11571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return init_library(si);
11581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
11591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
11601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* TODO:
11611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *   notify gdb of unload
11621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *   for non-prelinked libraries, find a way to decrement libbase
11631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
11641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic void call_destructors(soinfo *si);
11651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectunsigned unload_library(soinfo *si)
11661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
11671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned *d;
11681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (si->refcount == 1) {
11691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("%5d unloading '%s'\n", pid, si->name);
11701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        call_destructors(si);
11711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
11721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        for(d = si->dynamic; *d; d += 2) {
11731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if(d[0] == DT_NEEDED){
11746ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev                soinfo *lsi = (soinfo *)d[1];
11756ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev                d[1] = 0;
11766ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev                if (validate_soinfo(lsi)) {
11776ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev                    TRACE("%5d %s needs to unload %s\n", pid,
11786ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev                          si->name, lsi->name);
11791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    unload_library(lsi);
11806ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev                }
11811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                else
11826ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev                    DL_ERR("%5d %s: could not unload dependent library",
11836ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev                           pid, si->name);
11841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
11851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
11861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
11871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        munmap((char *)si->base, si->size);
11881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (si->ba_index >= 0) {
11891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            PRINT("%5d releasing library '%s' address space at %08x "\
11901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                  "through buddy allocator.\n",
11911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                  pid, si->name, si->base);
11921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            ba_free(si->ba_index);
11931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
11945e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev        notify_gdb_of_unload(si);
11951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        free_info(si);
11961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        si->refcount = 0;
11971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
11981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    else {
11991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        si->refcount--;
12001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        PRINT("%5d not unloading '%s', decrementing refcount to %d\n",
12011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              pid, si->name, si->refcount);
12021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
12031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return si->refcount;
12041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
12051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
12061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* TODO: don't use unsigned for addrs below. It works, but is not
12071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * ideal. They should probably be either uint32_t, Elf32_Addr, or unsigned
12081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * long.
12091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
12101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic int reloc_library(soinfo *si, Elf32_Rel *rel, unsigned count)
12111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
12121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Sym *symtab = si->symtab;
12131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    const char *strtab = si->strtab;
12141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Sym *s;
12151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned base;
12161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Rel *start = rel;
12171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned idx;
12181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
12191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for (idx = 0; idx < count; ++idx) {
12201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        unsigned type = ELF32_R_TYPE(rel->r_info);
12211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        unsigned sym = ELF32_R_SYM(rel->r_info);
12221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        unsigned reloc = (unsigned)(rel->r_offset + si->base);
12231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        unsigned sym_addr = 0;
12241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        char *sym_name = NULL;
12251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
12261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        DEBUG("%5d Processing '%s' relocation at index %d\n", pid,
12271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              si->name, idx);
12281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if(sym != 0) {
1229d1b40d8c69dfca94185ea9231f6cb16f70c02e39Dima Zavin            sym_name = (char *)(strtab + symtab[sym].st_name);
1230d1b40d8c69dfca94185ea9231f6cb16f70c02e39Dima Zavin            s = _do_lookup(si, sym_name, &base);
12311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if(s == 0) {
1232d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling                DL_ERR("%5d cannot locate '%s'...", pid, sym_name);
12331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                return -1;
12341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
12351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if 0
12361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if((base == 0) && (si->base != 0)){
12371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    /* linking from libraries to main image is bad */
1238d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling                DL_ERR("%5d cannot locate '%s'...",
12391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                       pid, strtab + symtab[sym].st_name);
12401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                return -1;
12411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
12421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
12431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if ((s->st_shndx == SHN_UNDEF) && (s->st_value != 0)) {
12442e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin                DL_ERR("%5d In '%s', shndx=%d && value=0x%08x. We do not "
1245d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling                      "handle this yet", pid, si->name, s->st_shndx,
12461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                      s->st_value);
12471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                return -1;
12481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
12491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            sym_addr = (unsigned)(s->st_value + base);
12501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            COUNT_RELOC(RELOC_SYMBOL);
12511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        } else {
12521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            s = 0;
12531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
12541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
12551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* TODO: This is ugly. Split up the relocations by arch into
12561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * different files.
12571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
12581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        switch(type){
12591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if defined(ANDROID_ARM_LINKER)
12601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case R_ARM_JUMP_SLOT:
12611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            COUNT_RELOC(RELOC_ABSOLUTE);
12621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            MARK(rel->r_offset);
12631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            TRACE_TYPE(RELO, "%5d RELO JMP_SLOT %08x <- %08x %s\n", pid,
12641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                       reloc, sym_addr, sym_name);
12651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            *((unsigned*)reloc) = sym_addr;
12661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
12671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case R_ARM_GLOB_DAT:
12681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            COUNT_RELOC(RELOC_ABSOLUTE);
12691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            MARK(rel->r_offset);
12701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            TRACE_TYPE(RELO, "%5d RELO GLOB_DAT %08x <- %08x %s\n", pid,
12711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                       reloc, sym_addr, sym_name);
12721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            *((unsigned*)reloc) = sym_addr;
12731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
12741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case R_ARM_ABS32:
12751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            COUNT_RELOC(RELOC_ABSOLUTE);
12761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            MARK(rel->r_offset);
12771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            TRACE_TYPE(RELO, "%5d RELO ABS %08x <- %08x %s\n", pid,
12781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                       reloc, sym_addr, sym_name);
12791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            *((unsigned*)reloc) += sym_addr;
12801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
12811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#elif defined(ANDROID_X86_LINKER)
12821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case R_386_JUMP_SLOT:
12831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            COUNT_RELOC(RELOC_ABSOLUTE);
12841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            MARK(rel->r_offset);
12851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            TRACE_TYPE(RELO, "%5d RELO JMP_SLOT %08x <- %08x %s\n", pid,
12861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                       reloc, sym_addr, sym_name);
12871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            *((unsigned*)reloc) = sym_addr;
12881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
12891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case R_386_GLOB_DAT:
12901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            COUNT_RELOC(RELOC_ABSOLUTE);
12911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            MARK(rel->r_offset);
12921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            TRACE_TYPE(RELO, "%5d RELO GLOB_DAT %08x <- %08x %s\n", pid,
12931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                       reloc, sym_addr, sym_name);
12941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            *((unsigned*)reloc) = sym_addr;
12951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
12961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif /* ANDROID_*_LINKER */
12971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
12981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if defined(ANDROID_ARM_LINKER)
12991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case R_ARM_RELATIVE:
13001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#elif defined(ANDROID_X86_LINKER)
13011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case R_386_RELATIVE:
13021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif /* ANDROID_*_LINKER */
13031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            COUNT_RELOC(RELOC_RELATIVE);
13041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            MARK(rel->r_offset);
13051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if(sym){
1306d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling                DL_ERR("%5d odd RELATIVE form...", pid);
13071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                return -1;
13081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
13091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            TRACE_TYPE(RELO, "%5d RELO RELATIVE %08x <- +%08x\n", pid,
13101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                       reloc, si->base);
13111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            *((unsigned*)reloc) += si->base;
13121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
13131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
13141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if defined(ANDROID_X86_LINKER)
13151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case R_386_32:
13161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            COUNT_RELOC(RELOC_RELATIVE);
13171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            MARK(rel->r_offset);
13181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
13191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            TRACE_TYPE(RELO, "%5d RELO R_386_32 %08x <- +%08x %s\n", pid,
13201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                       reloc, sym_addr, sym_name);
13211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            *((unsigned *)reloc) += (unsigned)sym_addr;
13221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
13231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
13241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case R_386_PC32:
13251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            COUNT_RELOC(RELOC_RELATIVE);
13261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            MARK(rel->r_offset);
13271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            TRACE_TYPE(RELO, "%5d RELO R_386_PC32 %08x <- "
13281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                       "+%08x (%08x - %08x) %s\n", pid, reloc,
13291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                       (sym_addr - reloc), sym_addr, reloc, sym_name);
13301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            *((unsigned *)reloc) += (unsigned)(sym_addr - reloc);
13311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
13321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif /* ANDROID_X86_LINKER */
13331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
13341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#ifdef ANDROID_ARM_LINKER
13351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case R_ARM_COPY:
13361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            COUNT_RELOC(RELOC_COPY);
13371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            MARK(rel->r_offset);
13381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            TRACE_TYPE(RELO, "%5d RELO %08x <- %d @ %08x %s\n", pid,
13391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                       reloc, s->st_size, sym_addr, sym_name);
13401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            memcpy((void*)reloc, (void*)sym_addr, s->st_size);
13411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
13425e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev        case R_ARM_NONE:
13435e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev            break;
13441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif /* ANDROID_ARM_LINKER */
13451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
13461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        default:
1347d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling            DL_ERR("%5d unknown reloc type %d @ %p (%d)",
13481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                  pid, type, rel, (int) (rel - start));
13491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return -1;
13501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
13511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        rel++;
13521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
13531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return 0;
13541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
13551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
13568215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner
13578215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner/* Please read the "Initialization and Termination functions" functions.
13588215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner * of the linker design note in bionic/linker/README.TXT to understand
13598215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner * what the following code is doing.
13608215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner *
13618215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner * The important things to remember are:
13628215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner *
13638215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner *   DT_PREINIT_ARRAY must be called first for executables, and should
13648215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner *   not appear in shared libraries.
13658215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner *
13668215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner *   DT_INIT should be called before DT_INIT_ARRAY if both are present
13678215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner *
13688215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner *   DT_FINI should be called after DT_FINI_ARRAY if both are present
13698215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner *
13708215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner *   DT_FINI_ARRAY must be parsed in reverse order.
13718215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner */
13728215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner
13738215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turnerstatic void call_array(unsigned *ctor, int count, int reverse)
13741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
13758215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner    int n, inc = 1;
13768215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner
13778215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner    if (reverse) {
13788215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner        ctor += (count-1);
13798215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner        inc   = -1;
13808215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner    }
13818215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner
13828215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner    for(n = count; n > 0; n--) {
13838215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner        TRACE("[ %5d Looking at %s *0x%08x == 0x%08x ]\n", pid,
13848215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner              reverse ? "dtor" : "ctor",
13851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              (unsigned)ctor, (unsigned)*ctor);
13868215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner        void (*func)() = (void (*)()) *ctor;
13878215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner        ctor += inc;
13881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if(((int) func == 0) || ((int) func == -1)) continue;
13891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d Calling func @ 0x%08x ]\n", pid, (unsigned)func);
13901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        func();
13911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
13921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
13931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
13941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic void call_constructors(soinfo *si)
13951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
13961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (si->flags & FLAG_EXE) {
13971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d Calling preinit_array @ 0x%08x [%d] for '%s' ]\n",
13981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              pid, (unsigned)si->preinit_array, si->preinit_array_count,
13991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              si->name);
14008215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner        call_array(si->preinit_array, si->preinit_array_count, 0);
14011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d Done calling preinit_array for '%s' ]\n", pid, si->name);
14021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    } else {
14031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (si->preinit_array) {
14042e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin            DL_ERR("%5d Shared library '%s' has a preinit_array table @ 0x%08x."
1405d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling                   " This is INVALID.", pid, si->name,
14062e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin                   (unsigned)si->preinit_array);
14071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
14081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
14091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
14101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (si->init_func) {
14111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d Calling init_func @ 0x%08x for '%s' ]\n", pid,
14121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              (unsigned)si->init_func, si->name);
14131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        si->init_func();
14141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d Done calling init_func for '%s' ]\n", pid, si->name);
14151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
14161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
14171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (si->init_array) {
14181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d Calling init_array @ 0x%08x [%d] for '%s' ]\n", pid,
14191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              (unsigned)si->init_array, si->init_array_count, si->name);
14208215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner        call_array(si->init_array, si->init_array_count, 0);
14211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d Done calling init_array for '%s' ]\n", pid, si->name);
14221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
14231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
14241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
14258215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner
14261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic void call_destructors(soinfo *si)
14271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
14281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (si->fini_array) {
14291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d Calling fini_array @ 0x%08x [%d] for '%s' ]\n", pid,
14301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              (unsigned)si->fini_array, si->fini_array_count, si->name);
14318215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner        call_array(si->fini_array, si->fini_array_count, 1);
14321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d Done calling fini_array for '%s' ]\n", pid, si->name);
14331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
14341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
14351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (si->fini_func) {
14361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d Calling fini_func @ 0x%08x for '%s' ]\n", pid,
14371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              (unsigned)si->fini_func, si->name);
14381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        si->fini_func();
14391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d Done calling fini_func for '%s' ]\n", pid, si->name);
14401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
14411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
14421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
14431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* Force any of the closed stdin, stdout and stderr to be associated with
14441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project   /dev/null. */
14451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic int nullify_closed_stdio (void)
14461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
14471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    int dev_null, i, status;
14481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    int return_value = 0;
14491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
14501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    dev_null = open("/dev/null", O_RDWR);
14511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (dev_null < 0) {
1452d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling        DL_ERR("Cannot open /dev/null.");
14531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return -1;
14541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
14551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    TRACE("[ %5d Opened /dev/null file-descriptor=%d]\n", pid, dev_null);
14561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
14571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* If any of the stdio file descriptors is valid and not associated
14581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project       with /dev/null, dup /dev/null to it.  */
14591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for (i = 0; i < 3; i++) {
14601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        /* If it is /dev/null already, we are done. */
14611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (i == dev_null)
14621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            continue;
14631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
14641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d Nullifying stdio file descriptor %d]\n", pid, i);
14651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        /* The man page of fcntl does not say that fcntl(..,F_GETFL)
14661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project           can be interrupted but we do this just to be safe. */
14671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        do {
14681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project          status = fcntl(i, F_GETFL);
14691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        } while (status < 0 && errno == EINTR);
14701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
14711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        /* If file is openned, we are good. */
14721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (status >= 0)
14731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project          continue;
14741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
14751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        /* The only error we allow is that the file descriptor does not
14761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project           exist, in which case we dup /dev/null to it. */
14771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (errno != EBADF) {
1478d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling            DL_ERR("nullify_stdio: unhandled error %s", strerror(errno));
14791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return_value = -1;
14801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            continue;
14811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
14821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
14831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        /* Try dupping /dev/null to this stdio file descriptor and
14841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project           repeat if there is a signal.  Note that any errors in closing
14851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project           the stdio descriptor are lost.  */
14861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        do {
14871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            status = dup2(dev_null, i);
14881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        } while (status < 0 && errno == EINTR);
14892e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin
14901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (status < 0) {
1491d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling            DL_ERR("nullify_stdio: dup2 error %s", strerror(errno));
14921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return_value = -1;
14931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            continue;
14941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
14951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
14961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
14971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* If /dev/null is not one of the stdio file descriptors, close it. */
14981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (dev_null > 2) {
14991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d Closing /dev/null file-descriptor=%d]\n", pid, dev_null);
15002e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin        do {
15011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            status = close(dev_null);
15021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        } while (status < 0 && errno == EINTR);
15031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
15041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (status < 0) {
1505d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling            DL_ERR("nullify_stdio: close error %s", strerror(errno));
15061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return_value = -1;
15071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
15081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
15091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
15101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return return_value;
15111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
15121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
15131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic int link_image(soinfo *si, unsigned wr_offset)
15141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
15151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned *d;
15161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Phdr *phdr = si->phdr;
15171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    int phnum = si->phnum;
15181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
15191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    INFO("[ %5d linking %s ]\n", pid, si->name);
15201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    DEBUG("%5d si->base = 0x%08x si->flags = 0x%08x\n", pid,
15211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project          si->base, si->flags);
15221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
15231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (si->flags & FLAG_EXE) {
15241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        /* Locate the needed program segments (DYNAMIC/ARM_EXIDX) for
15251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project         * linkage info if this is the executable. If this was a
15261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project         * dynamic lib, that would have been done at load time.
15271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project         *
15281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project         * TODO: It's unfortunate that small pieces of this are
15291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project         * repeated from the load_library routine. Refactor this just
15301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project         * slightly to reuse these bits.
15311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project         */
15321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        si->size = 0;
15331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        for(; phnum > 0; --phnum, ++phdr) {
15341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#ifdef ANDROID_ARM_LINKER
15351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if(phdr->p_type == PT_ARM_EXIDX) {
15361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                /* exidx entries (used for stack unwinding) are 8 bytes each.
15371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                 */
15381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                si->ARM_exidx = (unsigned *)phdr->p_vaddr;
15391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                si->ARM_exidx_count = phdr->p_memsz / 8;
15401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
15411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
15421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if (phdr->p_type == PT_LOAD) {
15431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                /* For the executable, we use the si->size field only in
15441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                   dl_unwind_find_exidx(), so the meaning of si->size
15451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                   is not the size of the executable; it is the last
15461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                   virtual address of the loadable part of the executable;
15471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                   since si->base == 0 for an executable, we use the
15481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                   range [0, si->size) to determine whether a PC value
15491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                   falls within the executable section.  Of course, if
15501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                   a value is below phdr->p_vaddr, it's not in the
15511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                   executable section, but a) we shouldn't be asking for
15521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                   such a value anyway, and b) if we have to provide
15531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                   an EXIDX for such a value, then the executable's
15541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                   EXIDX is probably the better choice.
15551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                */
15561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                DEBUG_DUMP_PHDR(phdr, "PT_LOAD", pid);
15571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                if (phdr->p_vaddr + phdr->p_memsz > si->size)
15581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    si->size = phdr->p_vaddr + phdr->p_memsz;
15591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                /* try to remember what range of addresses should be write
15601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                 * protected */
15611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                if (!(phdr->p_flags & PF_W)) {
15621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    unsigned _end;
15631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
15641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    if (phdr->p_vaddr < si->wrprotect_start)
15651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                        si->wrprotect_start = phdr->p_vaddr;
15661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    _end = (((phdr->p_vaddr + phdr->p_memsz + PAGE_SIZE - 1) &
15671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                             (~PAGE_MASK)));
15681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    if (_end > si->wrprotect_end)
15691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                        si->wrprotect_end = _end;
15701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                }
15711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            } else if (phdr->p_type == PT_DYNAMIC) {
15721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                if (si->dynamic != (unsigned *)-1) {
15732e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin                    DL_ERR("%5d multiple PT_DYNAMIC segments found in '%s'. "
1574d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling                          "Segment at 0x%08x, previously one found at 0x%08x",
15751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                          pid, si->name, si->base + phdr->p_vaddr,
15761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                          (unsigned)si->dynamic);
15771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    goto fail;
15781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                }
15791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                DEBUG_DUMP_PHDR(phdr, "PT_DYNAMIC", pid);
15801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                si->dynamic = (unsigned *) (si->base + phdr->p_vaddr);
15811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
15821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
15831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
15841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
15851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (si->dynamic == (unsigned *)-1) {
1586d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling        DL_ERR("%5d missing PT_DYNAMIC?!", pid);
15871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        goto fail;
15881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
15891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
15901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    DEBUG("%5d dynamic = %p\n", pid, si->dynamic);
15911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
15921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* extract useful information from dynamic section */
15931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for(d = si->dynamic; *d; d++){
15941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        DEBUG("%5d d = %p, d[0] = 0x%08x d[1] = 0x%08x\n", pid, d, d[0], d[1]);
15951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        switch(*d++){
15961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_HASH:
15971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->nbucket = ((unsigned *) (si->base + *d))[0];
15981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->nchain = ((unsigned *) (si->base + *d))[1];
15991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->bucket = (unsigned *) (si->base + *d + 8);
16001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->chain = (unsigned *) (si->base + *d + 8 + si->nbucket * 4);
16011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
16021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_STRTAB:
16031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->strtab = (const char *) (si->base + *d);
16041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
16051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_SYMTAB:
16061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->symtab = (Elf32_Sym *) (si->base + *d);
16071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
16081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_PLTREL:
16091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if(*d != DT_REL) {
1610d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling                DL_ERR("DT_RELA not supported");
16111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                goto fail;
16121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
16131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
16141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_JMPREL:
16151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->plt_rel = (Elf32_Rel*) (si->base + *d);
16161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
16171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_PLTRELSZ:
16181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->plt_rel_count = *d / 8;
16191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
16201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_REL:
16211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->rel = (Elf32_Rel*) (si->base + *d);
16221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
16231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_RELSZ:
16241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->rel_count = *d / 8;
16251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
16261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_PLTGOT:
16271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            /* Save this in case we decide to do lazy binding. We don't yet. */
16281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->plt_got = (unsigned *)(si->base + *d);
16291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
16301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_DEBUG:
16311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            // Set the DT_DEBUG entry to the addres of _r_debug for GDB
16321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            *d = (int) &_r_debug;
16331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
16341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_RELA:
1635d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling            DL_ERR("%5d DT_RELA not supported", pid);
16361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            goto fail;
16371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_INIT:
16381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->init_func = (void (*)(void))(si->base + *d);
16391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            DEBUG("%5d %s constructors (init func) found at %p\n",
16401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                  pid, si->name, si->init_func);
16411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
16421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_FINI:
16431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->fini_func = (void (*)(void))(si->base + *d);
16441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            DEBUG("%5d %s destructors (fini func) found at %p\n",
16451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                  pid, si->name, si->fini_func);
16461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
16471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_INIT_ARRAY:
16481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->init_array = (unsigned *)(si->base + *d);
16491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            DEBUG("%5d %s constructors (init_array) found at %p\n",
16501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                  pid, si->name, si->init_array);
16511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
16521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_INIT_ARRAYSZ:
16531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->init_array_count = ((unsigned)*d) / sizeof(Elf32_Addr);
16541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
16551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_FINI_ARRAY:
16561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->fini_array = (unsigned *)(si->base + *d);
16571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            DEBUG("%5d %s destructors (fini_array) found at %p\n",
16581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                  pid, si->name, si->fini_array);
16591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
16601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_FINI_ARRAYSZ:
16611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->fini_array_count = ((unsigned)*d) / sizeof(Elf32_Addr);
16621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
16631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_PREINIT_ARRAY:
16641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->preinit_array = (unsigned *)(si->base + *d);
16651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            DEBUG("%5d %s constructors (preinit_array) found at %p\n",
16661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                  pid, si->name, si->preinit_array);
16671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
16681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_PREINIT_ARRAYSZ:
16691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->preinit_array_count = ((unsigned)*d) / sizeof(Elf32_Addr);
16701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
16711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_TEXTREL:
16721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            /* TODO: make use of this. */
16731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            /* this means that we might have to write into where the text
16741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             * segment was loaded during relocation... Do something with
16751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             * it.
16761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             */
16771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            DEBUG("%5d Text segment should be writable during relocation.\n",
16781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                  pid);
16791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
16801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
16811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
16821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
16831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    DEBUG("%5d si->base = 0x%08x, si->strtab = %p, si->symtab = %p\n",
16841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project           pid, si->base, si->strtab, si->symtab);
16851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
16861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if((si->strtab == 0) || (si->symtab == 0)) {
1687d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling        DL_ERR("%5d missing essential tables", pid);
16881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        goto fail;
16891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
16901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
16911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for(d = si->dynamic; *d; d += 2) {
16921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if(d[0] == DT_NEEDED){
16931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            DEBUG("%5d %s needs %s\n", pid, si->name, si->strtab + d[1]);
16942e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin            soinfo *lsi = find_library(si->strtab + d[1]);
16951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if(lsi == 0) {
16960353195f344666256dba474a15c9ba22cf0cccc9Dima Zavin                strlcpy(tmp_err_buf, linker_get_error(), sizeof(tmp_err_buf));
1697d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling                DL_ERR("%5d could not load needed library '%s' for '%s' (%s)",
16980353195f344666256dba474a15c9ba22cf0cccc9Dima Zavin                       pid, si->strtab + d[1], si->name, tmp_err_buf);
16991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                goto fail;
17001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
17016ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev            /* Save the soinfo of the loaded DT_NEEDED library in the payload
17026ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev               of the DT_NEEDED entry itself, so that we can retrieve the
17036ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev               soinfo directly later from the dynamic segment.  This is a hack,
17046ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev               but it allows us to map from DT_NEEDED to soinfo efficiently
17056ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev               later on when we resolve relocations, trying to look up a symgol
17066ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev               with dlsym().
17076ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev            */
17086ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev            d[1] = (unsigned)lsi;
17091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            lsi->refcount++;
17101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
17111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
17121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
17131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if(si->plt_rel) {
17141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        DEBUG("[ %5d relocating %s plt ]\n", pid, si->name );
17151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if(reloc_library(si, si->plt_rel, si->plt_rel_count))
17161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            goto fail;
17171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
17181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if(si->rel) {
17191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        DEBUG("[ %5d relocating %s ]\n", pid, si->name );
17201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if(reloc_library(si, si->rel, si->rel_count))
17211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            goto fail;
17221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
17231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
17241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->flags |= FLAG_LINKED;
17251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    DEBUG("[ %5d finished linking %s ]\n", pid, si->name);
17261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
17271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if 0
17281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* This is the way that the old dynamic linker did protection of
17291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * non-writable areas. It would scan section headers and find where
17301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * .text ended (rather where .data/.bss began) and assume that this is
17311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * the upper range of the non-writable area. This is too coarse,
17321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * and is kept here for reference until we fully move away from single
17331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * segment elf objects. See the code in get_wr_offset (also #if'd 0)
17341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * that made this possible.
17351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     */
17361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if(wr_offset < 0xffffffff){
17371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        mprotect((void*) si->base, wr_offset, PROT_READ | PROT_EXEC);
17381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
17391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#else
17401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* TODO: Verify that this does the right thing in all cases, as it
17411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * presently probably does not. It is possible that an ELF image will
17421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * come with multiple read-only segments. What we ought to do is scan
17431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * the program headers again and mprotect all the read-only segments.
17441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * To prevent re-scanning the program header, we would have to build a
17451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * list of loadable segments in si, and then scan that instead. */
17461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (si->wrprotect_start != 0xffffffff && si->wrprotect_end != 0) {
17471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        mprotect((void *)si->wrprotect_start,
17481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                 si->wrprotect_end - si->wrprotect_start,
17491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                 PROT_READ | PROT_EXEC);
17501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
17511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
17521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
17531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* If this is a SET?ID program, dup /dev/null to opened stdin,
17541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project       stdout and stderr to close a security hole described in:
17551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
17561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    ftp://ftp.freebsd.org/pub/FreeBSD/CERT/advisories/FreeBSD-SA-02:23.stdio.asc
17571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
17581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     */
17591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (getuid() != geteuid() || getgid() != getegid())
17601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        nullify_closed_stdio ();
17611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    call_constructors(si);
17621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    notify_gdb_of_load(si);
17631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return 0;
17641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
17651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectfail:
17661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    ERROR("failed to link %s\n", si->name);
17671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->flags |= FLAG_ERROR;
17681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return -1;
17691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
17701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1771bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartleystatic void parse_library_path(char *path, char *delim)
1772bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley{
1773bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley    size_t len;
1774bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley    char *ldpaths_bufp = ldpaths_buf;
1775bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley    int i = 0;
1776bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley
1777bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley    len = strlcpy(ldpaths_buf, path, sizeof(ldpaths_buf));
1778bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley
1779bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley    while (i < LDPATH_MAX && (ldpaths[i] = strsep(&ldpaths_bufp, delim))) {
1780bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley        if (*ldpaths[i] != '\0')
1781bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley            ++i;
1782bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley    }
1783bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley
1784bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley    /* Forget the last path if we had to truncate; this occurs if the 2nd to
1785bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley     * last char isn't '\0' (i.e. not originally a delim). */
1786bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley    if (i > 0 && len >= sizeof(ldpaths_buf) &&
1787bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley            ldpaths_buf[sizeof(ldpaths_buf) - 2] != '\0') {
1788bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley        ldpaths[i - 1] = NULL;
1789bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley    } else {
1790bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley        ldpaths[i] = NULL;
1791bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley    }
1792bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley}
1793bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley
17941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint main(int argc, char **argv)
17951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
17961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return 0;
17971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
17981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
17991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define ANDROID_TLS_SLOTS  BIONIC_TLS_SLOTS
18001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
18011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic void * __tls_area[ANDROID_TLS_SLOTS];
18021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
18031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectunsigned __linker_init(unsigned **elfdata)
18041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
18051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    static soinfo linker_soinfo;
18061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
18071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    int argc = (int) *elfdata;
18081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    char **argv = (char**) (elfdata + 1);
18091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned *vecs = (unsigned*) (argv + argc + 1);
18101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    soinfo *si;
18111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    struct link_map * map;
1812bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley    char *ldpath_env = NULL;
18131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1814ef0bd1857041ffde069cf52138aaf22c1af7130eDavid 'Digit' Turner    /* Setup a temporary TLS area that is used to get a working
1815ef0bd1857041ffde069cf52138aaf22c1af7130eDavid 'Digit' Turner     * errno for system calls.
1816ef0bd1857041ffde069cf52138aaf22c1af7130eDavid 'Digit' Turner     */
1817ef0bd1857041ffde069cf52138aaf22c1af7130eDavid 'Digit' Turner    __set_tls(__tls_area);
1818ef0bd1857041ffde069cf52138aaf22c1af7130eDavid 'Digit' Turner
18191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    pid = getpid();
18201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
18211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if TIMING
18221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    struct timeval t0, t1;
18231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    gettimeofday(&t0, 0);
18241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
18251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1826ef0bd1857041ffde069cf52138aaf22c1af7130eDavid 'Digit' Turner    /* NOTE: we store the elfdata pointer on a special location
1827ef0bd1857041ffde069cf52138aaf22c1af7130eDavid 'Digit' Turner     *       of the temporary TLS area in order to pass it to
1828ef0bd1857041ffde069cf52138aaf22c1af7130eDavid 'Digit' Turner     *       the C Library's runtime initializer.
1829ef0bd1857041ffde069cf52138aaf22c1af7130eDavid 'Digit' Turner     *
1830ef0bd1857041ffde069cf52138aaf22c1af7130eDavid 'Digit' Turner     *       The initializer must clear the slot and reset the TLS
1831ef0bd1857041ffde069cf52138aaf22c1af7130eDavid 'Digit' Turner     *       to point to a different location to ensure that no other
1832ef0bd1857041ffde069cf52138aaf22c1af7130eDavid 'Digit' Turner     *       shared library constructor can access it.
1833ef0bd1857041ffde069cf52138aaf22c1af7130eDavid 'Digit' Turner     */
1834ef0bd1857041ffde069cf52138aaf22c1af7130eDavid 'Digit' Turner    __tls_area[TLS_SLOT_BIONIC_PREINIT] = elfdata;
18351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
18361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    debugger_init();
18371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
18381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        /* skip past the environment */
18391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    while(vecs[0] != 0) {
18401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if(!strncmp((char*) vecs[0], "DEBUG=", 6)) {
18411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            debug_verbosity = atoi(((char*) vecs[0]) + 6);
1842bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley        } else if(!strncmp((char*) vecs[0], "LD_LIBRARY_PATH=", 16)) {
1843bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley            ldpath_env = (char*) vecs[0] + 16;
18441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
18451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        vecs++;
18461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
18471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    vecs++;
18481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
18491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    INFO("[ android linker & debugger ]\n");
18501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    DEBUG("%5d elfdata @ 0x%08x\n", pid, (unsigned)elfdata);
18511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
18521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si = alloc_info(argv[0]);
18531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if(si == 0) {
18541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        exit(-1);
18551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
18561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
18571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        /* bootstrap the link map, the main exe always needs to be first */
18581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->flags |= FLAG_EXE;
18591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    map = &(si->linkmap);
18601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
18611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    map->l_addr = 0;
18621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    map->l_name = argv[0];
18631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    map->l_prev = NULL;
18641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    map->l_next = NULL;
18651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
18661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    _r_debug.r_map = map;
18671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    r_debug_tail = map;
18681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
18691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        /* gdb expects the linker to be in the debug shared object list,
18701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project         * and we need to make sure that the reported load address is zero.
18711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project         * Without this, gdb gets the wrong idea of where rtld_db_dlactivity()
18721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project         * is.  Don't use alloc_info(), because the linker shouldn't
18731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project         * be on the soinfo list.
18741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project         */
18751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    strcpy((char*) linker_soinfo.name, "/system/bin/linker");
18761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    linker_soinfo.flags = 0;
18771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    linker_soinfo.base = 0;     // This is the important part; must be zero.
18781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    insert_soinfo_into_debug_map(&linker_soinfo);
18791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
18801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        /* extract information passed from the kernel */
18811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    while(vecs[0] != 0){
18821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        switch(vecs[0]){
18831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case AT_PHDR:
18841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->phdr = (Elf32_Phdr*) vecs[1];
18851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
18861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case AT_PHNUM:
18871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->phnum = (int) vecs[1];
18881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
18891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case AT_ENTRY:
18901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->entry = vecs[1];
18911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
18921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
18931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        vecs += 2;
18941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
18951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
18961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    ba_init();
18971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
18981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->base = 0;
18991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->dynamic = (unsigned *)-1;
19001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->wrprotect_start = 0xffffffff;
19011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->wrprotect_end = 0;
19021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1903bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley        /* Use LD_LIBRARY_PATH if we aren't setuid/setgid */
1904bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley    if (ldpath_env && getuid() == geteuid() && getgid() == getegid())
1905bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley        parse_library_path(ldpath_env, ":");
1906bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley
19072e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin    if(link_image(si, 0)) {
19082e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin        char errmsg[] = "CANNOT LINK EXECUTABLE\n";
19092e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin        write(2, __linker_dl_err_buf, strlen(__linker_dl_err_buf));
19102e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin        write(2, errmsg, sizeof(errmsg));
19111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        exit(-1);
19121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
19131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
19144a9afcb10151b083cd2d75253385615f459172edIliyan Malchev#if ALLOW_SYMBOLS_FROM_MAIN
19154a9afcb10151b083cd2d75253385615f459172edIliyan Malchev    /* Set somain after we've loaded all the libraries in order to prevent
19164a9afcb10151b083cd2d75253385615f459172edIliyan Malchev     * linking of symbols back to the main image, which is not set up at that
19174a9afcb10151b083cd2d75253385615f459172edIliyan Malchev     * point yet.
19184a9afcb10151b083cd2d75253385615f459172edIliyan Malchev     */
19194a9afcb10151b083cd2d75253385615f459172edIliyan Malchev    somain = si;
19204a9afcb10151b083cd2d75253385615f459172edIliyan Malchev#endif
19214a9afcb10151b083cd2d75253385615f459172edIliyan Malchev
19221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if TIMING
19231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    gettimeofday(&t1,NULL);
19241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    PRINT("LINKER TIME: %s: %d microseconds\n", argv[0], (int) (
19251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project               (((long long)t1.tv_sec * 1000000LL) + (long long)t1.tv_usec) -
19261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project               (((long long)t0.tv_sec * 1000000LL) + (long long)t0.tv_usec)
19271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project               ));
19281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
19291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if STATS
19301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    PRINT("RELO STATS: %s: %d abs, %d rel, %d copy, %d symbol\n", argv[0],
19311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project           linker_stats.reloc[RELOC_ABSOLUTE],
19321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project           linker_stats.reloc[RELOC_RELATIVE],
19331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project           linker_stats.reloc[RELOC_COPY],
19341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project           linker_stats.reloc[RELOC_SYMBOL]);
19351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
19361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if COUNT_PAGES
19371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    {
19381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        unsigned n;
19391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        unsigned i;
19401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        unsigned count = 0;
19411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        for(n = 0; n < 4096; n++){
19421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if(bitmask[n]){
19431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                unsigned x = bitmask[n];
19441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                for(i = 0; i < 8; i++){
19451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    if(x & 1) count++;
19461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    x >>= 1;
19471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                }
19481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
19491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
19501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        PRINT("PAGES MODIFIED: %s: %d (%dKB)\n", argv[0], count, count * 4);
19511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
19521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
19531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
19541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if TIMING || STATS || COUNT_PAGES
19551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    fflush(stdout);
19561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
19571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
19581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    TRACE("[ %5d Ready to execute '%s' @ 0x%08x ]\n", pid, si->name,
19591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project          si->entry);
19601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return si->entry;
19611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
1962