13b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes/*
23b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes * Copyright (C) 2007 The Android Open Source Project
33b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes *
43b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes * Licensed under the Apache License, Version 2.0 (the "License");
53b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes * you may not use this file except in compliance with the License.
63b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes * You may obtain a copy of the License at
73b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes *
83b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes *      http://www.apache.org/licenses/LICENSE-2.0
93b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes *
103b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes * Unless required by applicable law or agreed to in writing, software
113b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes * distributed under the License is distributed on an "AS IS" BASIS,
123b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes * See the License for the specific language governing permissions and
143b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes * limitations under the License.
153b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes */
163b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
175419b9474753d25dff947c7740532f86d130c0beElliott Hughes#include "linker.h"
185419b9474753d25dff947c7740532f86d130c0beElliott Hughes
193b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#include <dlfcn.h>
203b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#include <pthread.h>
213b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#include <stdio.h>
225419b9474753d25dff947c7740532f86d130c0beElliott Hughes#include <stdlib.h>
23012cb4583a5f8564059142bb1900ea3a31e7cfa9Torne (Richard Coles)#include <android/dlext.h>
243b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
255419b9474753d25dff947c7740532f86d130c0beElliott Hughes#include <bionic/pthread_internal.h>
26eb847bc8666842a3cfc9c06e8458ad1abebebaf0Elliott Hughes#include "private/bionic_tls.h"
27eb847bc8666842a3cfc9c06e8458ad1abebebaf0Elliott Hughes#include "private/ScopedPthreadMutexLocker.h"
28eb847bc8666842a3cfc9c06e8458ad1abebebaf0Elliott Hughes#include "private/ThreadLocalBuffer.h"
293b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
303b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes/* This file hijacks the symbols stubbed out in libdl.so. */
313b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
321728b2396591853345507a063ed6075dfd251706Elliott Hughesstatic pthread_mutex_t g_dl_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER;
333b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
345419b9474753d25dff947c7740532f86d130c0beElliott Hughesstatic const char* __bionic_set_dlerror(char* new_value) {
352a0b873065edb304fa2d1c54f8de663ea638b8abElliott Hughes  char** dlerror_slot = &reinterpret_cast<char**>(__get_tls())[TLS_SLOT_DLERROR];
363b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
375419b9474753d25dff947c7740532f86d130c0beElliott Hughes  const char* old_value = *dlerror_slot;
385419b9474753d25dff947c7740532f86d130c0beElliott Hughes  *dlerror_slot = new_value;
395419b9474753d25dff947c7740532f86d130c0beElliott Hughes  return old_value;
405419b9474753d25dff947c7740532f86d130c0beElliott Hughes}
413b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
425419b9474753d25dff947c7740532f86d130c0beElliott Hughesstatic void __bionic_format_dlerror(const char* msg, const char* detail) {
435419b9474753d25dff947c7740532f86d130c0beElliott Hughes  char* buffer = __get_thread()->dlerror_buffer;
445419b9474753d25dff947c7740532f86d130c0beElliott Hughes  strlcpy(buffer, msg, __BIONIC_DLERROR_BUFFER_SIZE);
453b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  if (detail != NULL) {
465419b9474753d25dff947c7740532f86d130c0beElliott Hughes    strlcat(buffer, ": ", __BIONIC_DLERROR_BUFFER_SIZE);
475419b9474753d25dff947c7740532f86d130c0beElliott Hughes    strlcat(buffer, detail, __BIONIC_DLERROR_BUFFER_SIZE);
483b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  }
495419b9474753d25dff947c7740532f86d130c0beElliott Hughes
505419b9474753d25dff947c7740532f86d130c0beElliott Hughes  __bionic_set_dlerror(buffer);
515419b9474753d25dff947c7740532f86d130c0beElliott Hughes}
525419b9474753d25dff947c7740532f86d130c0beElliott Hughes
535419b9474753d25dff947c7740532f86d130c0beElliott Hughesconst char* dlerror() {
545419b9474753d25dff947c7740532f86d130c0beElliott Hughes  const char* old_value = __bionic_set_dlerror(NULL);
555419b9474753d25dff947c7740532f86d130c0beElliott Hughes  return old_value;
563b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes}
573b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
58a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughesvoid android_get_LD_LIBRARY_PATH(char* buffer, size_t buffer_size) {
591728b2396591853345507a063ed6075dfd251706Elliott Hughes  ScopedPthreadMutexLocker locker(&g_dl_mutex);
60a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughes  do_android_get_LD_LIBRARY_PATH(buffer, buffer_size);
61a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughes}
62a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughes
63cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughesvoid android_update_LD_LIBRARY_PATH(const char* ld_library_path) {
641728b2396591853345507a063ed6075dfd251706Elliott Hughes  ScopedPthreadMutexLocker locker(&g_dl_mutex);
65cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes  do_android_update_LD_LIBRARY_PATH(ld_library_path);
66cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes}
67cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes
681a586293400d0e1d73e6eb82f7dfe9d2d9ed3c4bElliott Hughesstatic void* dlopen_ext(const char* filename, int flags, const android_dlextinfo* extinfo) {
691728b2396591853345507a063ed6075dfd251706Elliott Hughes  ScopedPthreadMutexLocker locker(&g_dl_mutex);
701a586293400d0e1d73e6eb82f7dfe9d2d9ed3c4bElliott Hughes  soinfo* result = do_dlopen(filename, flags, extinfo);
713b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  if (result == NULL) {
72650be4e584eeab3591b9e273bfd6d169eea60853Elliott Hughes    __bionic_format_dlerror("dlopen failed", linker_get_error_buffer());
733b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes    return NULL;
743b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  }
753b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  return result;
763b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes}
773b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
78b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanovvoid* android_dlopen_ext(const char* filename, int flags, const android_dlextinfo* extinfo) {
791a586293400d0e1d73e6eb82f7dfe9d2d9ed3c4bElliott Hughes  return dlopen_ext(filename, flags, extinfo);
80b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov}
81b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov
82012cb4583a5f8564059142bb1900ea3a31e7cfa9Torne (Richard Coles)void* dlopen(const char* filename, int flags) {
831a586293400d0e1d73e6eb82f7dfe9d2d9ed3c4bElliott Hughes  return dlopen_ext(filename, flags, NULL);
84012cb4583a5f8564059142bb1900ea3a31e7cfa9Torne (Richard Coles)}
85012cb4583a5f8564059142bb1900ea3a31e7cfa9Torne (Richard Coles)
863b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughesvoid* dlsym(void* handle, const char* symbol) {
871728b2396591853345507a063ed6075dfd251706Elliott Hughes  ScopedPthreadMutexLocker locker(&g_dl_mutex);
883b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
89ca1c80220e9b16fde7a761ca1c2c63dbe8071e0fDmitriy Ivanov#if !defined(__LP64__)
905419b9474753d25dff947c7740532f86d130c0beElliott Hughes  if (handle == NULL) {
915419b9474753d25dff947c7740532f86d130c0beElliott Hughes    __bionic_format_dlerror("dlsym library handle is null", NULL);
923b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes    return NULL;
933b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  }
94ca1c80220e9b16fde7a761ca1c2c63dbe8071e0fDmitriy Ivanov#endif
95ca1c80220e9b16fde7a761ca1c2c63dbe8071e0fDmitriy Ivanov
965419b9474753d25dff947c7740532f86d130c0beElliott Hughes  if (symbol == NULL) {
975419b9474753d25dff947c7740532f86d130c0beElliott Hughes    __bionic_format_dlerror("dlsym symbol name is null", NULL);
983b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes    return NULL;
993b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  }
1003b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
1013b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  soinfo* found = NULL;
1020266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  ElfW(Sym)* sym = NULL;
103acfc63760eef50cd451b80df8860d17bbab1ca33Colin Cross  if (handle == RTLD_DEFAULT) {
1049419420919ea846bbad5510850c7aaec95021648Dmitriy Ivanov    sym = dlsym_linear_lookup(symbol, &found, NULL);
105acfc63760eef50cd451b80df8860d17bbab1ca33Colin Cross  } else if (handle == RTLD_NEXT) {
1069419420919ea846bbad5510850c7aaec95021648Dmitriy Ivanov    void* caller_addr = __builtin_return_address(0);
1079419420919ea846bbad5510850c7aaec95021648Dmitriy Ivanov    soinfo* si = find_containing_library(caller_addr);
1089419420919ea846bbad5510850c7aaec95021648Dmitriy Ivanov
1093b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes    sym = NULL;
1109419420919ea846bbad5510850c7aaec95021648Dmitriy Ivanov    if (si && si->next) {
1119419420919ea846bbad5510850c7aaec95021648Dmitriy Ivanov      sym = dlsym_linear_lookup(symbol, &found, si->next);
1123b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes    }
1133b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  } else {
1149419420919ea846bbad5510850c7aaec95021648Dmitriy Ivanov    sym = dlsym_handle_lookup(reinterpret_cast<soinfo*>(handle), &found, symbol);
1153b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  }
1163b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
1179419420919ea846bbad5510850c7aaec95021648Dmitriy Ivanov  if (sym != NULL) {
1189419420919ea846bbad5510850c7aaec95021648Dmitriy Ivanov    unsigned bind = ELF_ST_BIND(sym->st_info);
1199419420919ea846bbad5510850c7aaec95021648Dmitriy Ivanov
1209419420919ea846bbad5510850c7aaec95021648Dmitriy Ivanov    if ((bind == STB_GLOBAL || bind == STB_WEAK) && sym->st_shndx != 0) {
1219419420919ea846bbad5510850c7aaec95021648Dmitriy Ivanov      return reinterpret_cast<void*>(sym->st_value + found->load_bias);
1229419420919ea846bbad5510850c7aaec95021648Dmitriy Ivanov    }
1239419420919ea846bbad5510850c7aaec95021648Dmitriy Ivanov
1249419420919ea846bbad5510850c7aaec95021648Dmitriy Ivanov    __bionic_format_dlerror("symbol found but not global", symbol);
1259419420919ea846bbad5510850c7aaec95021648Dmitriy Ivanov    return NULL;
1263b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  } else {
1275419b9474753d25dff947c7740532f86d130c0beElliott Hughes    __bionic_format_dlerror("undefined symbol", symbol);
1283b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes    return NULL;
1293b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  }
1303b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes}
1313b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
1323b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughesint dladdr(const void* addr, Dl_info* info) {
1331728b2396591853345507a063ed6075dfd251706Elliott Hughes  ScopedPthreadMutexLocker locker(&g_dl_mutex);
1343b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
1353b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  // Determine if this address can be found in any library currently mapped.
1363b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  soinfo* si = find_containing_library(addr);
1373b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  if (si == NULL) {
1383b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes    return 0;
1393b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  }
1403b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
1413b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  memset(info, 0, sizeof(Dl_info));
1423b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
1433b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  info->dli_fname = si->name;
1443b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  // Address at which the shared object is loaded.
145faf05bacd45719291b371f24b1b89543881b37f6Elliott Hughes  info->dli_fbase = reinterpret_cast<void*>(si->base);
1463b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
1473b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  // Determine if any symbol in the library contains the specified address.
1480266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  ElfW(Sym)* sym = dladdr_find_symbol(si, addr);
1493b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  if (sym != NULL) {
1503b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes    info->dli_sname = si->strtab + sym->st_name;
151faf05bacd45719291b371f24b1b89543881b37f6Elliott Hughes    info->dli_saddr = reinterpret_cast<void*>(si->load_bias + sym->st_value);
1523b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  }
1533b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
1543b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  return 1;
1553b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes}
1563b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
1573b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughesint dlclose(void* handle) {
1581728b2396591853345507a063ed6075dfd251706Elliott Hughes  ScopedPthreadMutexLocker locker(&g_dl_mutex);
159b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  do_dlclose(reinterpret_cast<soinfo*>(handle));
160b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  // dlclose has no defined errors.
161b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  return 0;
1623b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes}
1633b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
1643b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes// name_offset: starting index of the name in libdl_info.strtab
1653b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#define ELF32_SYM_INITIALIZER(name_offset, value, shndx) \
1663b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes    { name_offset, \
1673b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes      reinterpret_cast<Elf32_Addr>(reinterpret_cast<void*>(value)), \
1683b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes      /* st_size */ 0, \
1693b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes      (shndx == 0) ? 0 : (STB_GLOBAL << 4), \
1703b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes      /* st_other */ 0, \
171c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes      shndx, \
172c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes    }
173c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes
174c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#define ELF64_SYM_INITIALIZER(name_offset, value, shndx) \
175c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes    { name_offset, \
176c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes      (shndx == 0) ? 0 : (STB_GLOBAL << 4), \
177c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes      /* st_other */ 0, \
178c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes      shndx, \
179c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes      reinterpret_cast<Elf64_Addr>(reinterpret_cast<void*>(value)), \
180c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes      /* st_size */ 0, \
181c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes    }
182c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes
183a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughes#if defined(__arm__)
184012cb4583a5f8564059142bb1900ea3a31e7cfa9Torne (Richard Coles)  // 0000000 00011111 111112 22222222 2333333 3333444444444455555555556666666 6667777777777888888888899999 9999900000000001 1111111112222222222 333333333344444444445
185012cb4583a5f8564059142bb1900ea3a31e7cfa9Torne (Richard Coles)  // 0123456 78901234 567890 12345678 9012345 6789012345678901234567890123456 7890123456789012345678901234 5678901234567890 1234567890123456789 012345678901234567890
186a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughes#  define ANDROID_LIBDL_STRTAB \
187012cb4583a5f8564059142bb1900ea3a31e7cfa9Torne (Richard Coles)    "dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0android_update_LD_LIBRARY_PATH\0android_get_LD_LIBRARY_PATH\0dl_iterate_phdr\0android_dlopen_ext\0dl_unwind_find_exidx\0"
188a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughes#elif defined(__aarch64__) || defined(__i386__) || defined(__mips__) || defined(__x86_64__)
189012cb4583a5f8564059142bb1900ea3a31e7cfa9Torne (Richard Coles)  // 0000000 00011111 111112 22222222 2333333 3333444444444455555555556666666 6667777777777888888888899999 9999900000000001 1111111112222222222
190012cb4583a5f8564059142bb1900ea3a31e7cfa9Torne (Richard Coles)  // 0123456 78901234 567890 12345678 9012345 6789012345678901234567890123456 7890123456789012345678901234 5678901234567890 1234567890123456789
191a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughes#  define ANDROID_LIBDL_STRTAB \
192012cb4583a5f8564059142bb1900ea3a31e7cfa9Torne (Richard Coles)    "dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0android_update_LD_LIBRARY_PATH\0android_get_LD_LIBRARY_PATH\0dl_iterate_phdr\0android_dlopen_ext\0"
193a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughes#else
1949918665a45095ad135576f005c0e5307feb366a1Chris Dearman#  error Unsupported architecture. Only arm, arm64, mips, mips64, x86 and x86_64 are presently supported.
195a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughes#endif
196a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughes
1971728b2396591853345507a063ed6075dfd251706Elliott Hughesstatic ElfW(Sym) g_libdl_symtab[] = {
1983b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  // Total length of libdl_info.strtab, including trailing 0.
1993b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  // This is actually the STH_UNDEF entry. Technically, it's
2003b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  // supposed to have st_name == 0, but instead, it points to an index
2013b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  // in the strtab with a \0 to make iterating through the symtab easier.
2020266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  ELFW(SYM_INITIALIZER)(sizeof(ANDROID_LIBDL_STRTAB) - 1, NULL, 0),
2030266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  ELFW(SYM_INITIALIZER)(  0, &dlopen, 1),
2040266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  ELFW(SYM_INITIALIZER)(  7, &dlclose, 1),
2050266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  ELFW(SYM_INITIALIZER)( 15, &dlsym, 1),
2060266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  ELFW(SYM_INITIALIZER)( 21, &dlerror, 1),
2070266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  ELFW(SYM_INITIALIZER)( 29, &dladdr, 1),
2080266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  ELFW(SYM_INITIALIZER)( 36, &android_update_LD_LIBRARY_PATH, 1),
2090266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  ELFW(SYM_INITIALIZER)( 67, &android_get_LD_LIBRARY_PATH, 1),
2100266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  ELFW(SYM_INITIALIZER)( 95, &dl_iterate_phdr, 1),
211012cb4583a5f8564059142bb1900ea3a31e7cfa9Torne (Richard Coles)  ELFW(SYM_INITIALIZER)(111, &android_dlopen_ext, 1),
2124eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__arm__)
213012cb4583a5f8564059142bb1900ea3a31e7cfa9Torne (Richard Coles)  ELFW(SYM_INITIALIZER)(130, &dl_unwind_find_exidx, 1),
2143b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#endif
2153b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes};
2163b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
21722d629211d72adaf46f3fc48f59540f8e5798b1eElliott Hughes// Fake out a hash table with a single bucket.
21822d629211d72adaf46f3fc48f59540f8e5798b1eElliott Hughes//
2191728b2396591853345507a063ed6075dfd251706Elliott Hughes// A search of the hash table will look through g_libdl_symtab starting with index 1, then
2201728b2396591853345507a063ed6075dfd251706Elliott Hughes// use g_libdl_chains to find the next index to look at. g_libdl_chains should be set up to
2211728b2396591853345507a063ed6075dfd251706Elliott Hughes// walk through every element in g_libdl_symtab, and then end with 0 (sentinel value).
22222d629211d72adaf46f3fc48f59540f8e5798b1eElliott Hughes//
2231728b2396591853345507a063ed6075dfd251706Elliott Hughes// That is, g_libdl_chains should look like { 0, 2, 3, ... N, 0 } where N is the number
2241728b2396591853345507a063ed6075dfd251706Elliott Hughes// of actual symbols, or nelems(g_libdl_symtab)-1 (since the first element of g_libdl_symtab is not
225a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughes// a real symbol). (See soinfo_elf_lookup().)
22622d629211d72adaf46f3fc48f59540f8e5798b1eElliott Hughes//
227a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughes// Note that adding any new symbols here requires stubbing them out in libdl.
2281728b2396591853345507a063ed6075dfd251706Elliott Hughesstatic unsigned g_libdl_buckets[1] = { 1 };
2294eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__arm__)
2301728b2396591853345507a063ed6075dfd251706Elliott Hughesstatic unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0 };
23124053a461e7a20f34002262c1bb122023134989dChristopher Ferris#else
2321728b2396591853345507a063ed6075dfd251706Elliott Hughesstatic unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
23324053a461e7a20f34002262c1bb122023134989dChristopher Ferris#endif
2343b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
235d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov// Defined as global because we do not yet have access
236d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov// to synchronization functions __cxa_guard_* needed
237d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov// to define statics inside functions.
238d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovstatic soinfo __libdl_info;
239c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes
240d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov// This is used by the dynamic linker. Every process gets these symbols for free.
241d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovsoinfo* get_libdl_info() {
242d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  if (__libdl_info.name[0] == '\0') {
243d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov    // initialize
244d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov    strncpy(__libdl_info.name, "libdl.so", sizeof(__libdl_info.name));
245d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov    __libdl_info.flags = FLAG_LINKED | FLAG_NEW_SOINFO;
246d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov    __libdl_info.strtab = ANDROID_LIBDL_STRTAB;
247d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov    __libdl_info.symtab = g_libdl_symtab;
248d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov    __libdl_info.nbucket = sizeof(g_libdl_buckets)/sizeof(unsigned);
249d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov    __libdl_info.nchain = sizeof(g_libdl_chains)/sizeof(unsigned);
250d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov    __libdl_info.bucket = g_libdl_buckets;
251d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov    __libdl_info.chain = g_libdl_chains;
252d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov    __libdl_info.has_DT_SYMBOLIC = true;
253d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  }
2543b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
255d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  return &__libdl_info;
256d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov}
257