1 /* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 #include <dlfcn.h> 17 #include <pthread.h> 18 #include <stdio.h> 19 #include "linker.h" 20 #include "linker_format.h" 21 22 /* This file hijacks the symbols stubbed out in libdl.so. */ 23 24 #define DL_SUCCESS 0 25 #define DL_ERR_CANNOT_LOAD_LIBRARY 1 26 #define DL_ERR_INVALID_LIBRARY_HANDLE 2 27 #define DL_ERR_BAD_SYMBOL_NAME 3 28 #define DL_ERR_SYMBOL_NOT_FOUND 4 29 #define DL_ERR_SYMBOL_NOT_GLOBAL 5 30 31 static char dl_err_buf[1024]; 32 static const char *dl_err_str; 33 34 static const char *dl_errors[] = { 35 [DL_ERR_CANNOT_LOAD_LIBRARY] = "Cannot load library", 36 [DL_ERR_INVALID_LIBRARY_HANDLE] = "Invalid library handle", 37 [DL_ERR_BAD_SYMBOL_NAME] = "Invalid symbol name", 38 [DL_ERR_SYMBOL_NOT_FOUND] = "Symbol not found", 39 [DL_ERR_SYMBOL_NOT_GLOBAL] = "Symbol is not global", 40 }; 41 42 #define likely(expr) __builtin_expect (expr, 1) 43 #define unlikely(expr) __builtin_expect (expr, 0) 44 45 pthread_mutex_t dl_lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER; 46 47 static void set_dlerror(int err) 48 { 49 format_buffer(dl_err_buf, sizeof(dl_err_buf), "%s: %s", dl_errors[err], 50 linker_get_error()); 51 dl_err_str = (const char *)&dl_err_buf[0]; 52 }; 53 54 void *dlopen(const char *filename, int flag) 55 { 56 soinfo *ret; 57 58 pthread_mutex_lock(&dl_lock); 59 ret = find_library(filename); 60 if (unlikely(ret == NULL)) { 61 set_dlerror(DL_ERR_CANNOT_LOAD_LIBRARY); 62 } else { 63 call_constructors_recursive(ret); 64 ret->refcount++; 65 } 66 pthread_mutex_unlock(&dl_lock); 67 return ret; 68 } 69 70 const char *dlerror(void) 71 { 72 const char *tmp = dl_err_str; 73 dl_err_str = NULL; 74 return (const char *)tmp; 75 } 76 77 void *dlsym(void *handle, const char *symbol) 78 { 79 soinfo *found; 80 Elf32_Sym *sym; 81 unsigned bind; 82 83 pthread_mutex_lock(&dl_lock); 84 85 if(unlikely(handle == 0)) { 86 set_dlerror(DL_ERR_INVALID_LIBRARY_HANDLE); 87 goto err; 88 } 89 if(unlikely(symbol == 0)) { 90 set_dlerror(DL_ERR_BAD_SYMBOL_NAME); 91 goto err; 92 } 93 94 if(handle == RTLD_DEFAULT) { 95 sym = lookup(symbol, &found, NULL); 96 } else if(handle == RTLD_NEXT) { 97 void *ret_addr = __builtin_return_address(0); 98 soinfo *si = find_containing_library(ret_addr); 99 100 sym = NULL; 101 if(si && si->next) { 102 sym = lookup(symbol, &found, si->next); 103 } 104 } else { 105 found = (soinfo*)handle; 106 sym = lookup_in_library(found, symbol); 107 } 108 109 if(likely(sym != 0)) { 110 bind = ELF32_ST_BIND(sym->st_info); 111 112 if(likely((bind == STB_GLOBAL) && (sym->st_shndx != 0))) { 113 unsigned ret = sym->st_value + found->base; 114 pthread_mutex_unlock(&dl_lock); 115 return (void*)ret; 116 } 117 118 set_dlerror(DL_ERR_SYMBOL_NOT_GLOBAL); 119 } 120 else 121 set_dlerror(DL_ERR_SYMBOL_NOT_FOUND); 122 123 err: 124 pthread_mutex_unlock(&dl_lock); 125 return 0; 126 } 127 128 int dladdr(const void *addr, Dl_info *info) 129 { 130 int ret = 0; 131 132 pthread_mutex_lock(&dl_lock); 133 134 /* Determine if this address can be found in any library currently mapped */ 135 soinfo *si = find_containing_library(addr); 136 137 if(si) { 138 memset(info, 0, sizeof(Dl_info)); 139 140 info->dli_fname = si->name; 141 info->dli_fbase = (void*)si->base; 142 143 /* Determine if any symbol in the library contains the specified address */ 144 Elf32_Sym *sym = find_containing_symbol(addr, si); 145 146 if(sym != NULL) { 147 info->dli_sname = si->strtab + sym->st_name; 148 info->dli_saddr = (void*)(si->base + sym->st_value); 149 } 150 151 ret = 1; 152 } 153 154 pthread_mutex_unlock(&dl_lock); 155 156 return ret; 157 } 158 159 int dlclose(void *handle) 160 { 161 pthread_mutex_lock(&dl_lock); 162 (void)unload_library((soinfo*)handle); 163 pthread_mutex_unlock(&dl_lock); 164 return 0; 165 } 166 167 #if defined(ANDROID_ARM_LINKER) 168 // 0000000 00011111 111112 22222222 2333333 333344444444445555555 169 // 0123456 78901234 567890 12345678 9012345 678901234567890123456 170 #define ANDROID_LIBDL_STRTAB \ 171 "dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0dl_unwind_find_exidx\0" 172 173 #elif defined(ANDROID_X86_LINKER) 174 // 0000000 00011111 111112 22222222 2333333 3333444444444455 175 // 0123456 78901234 567890 12345678 9012345 6789012345678901 176 #define ANDROID_LIBDL_STRTAB \ 177 "dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0dl_iterate_phdr\0" 178 #else 179 #error Unsupported architecture. Only ARM and x86 are presently supported. 180 #endif 181 182 183 static Elf32_Sym libdl_symtab[] = { 184 // total length of libdl_info.strtab, including trailing 0 185 // This is actually the the STH_UNDEF entry. Technically, it's 186 // supposed to have st_name == 0, but instead, it points to an index 187 // in the strtab with a \0 to make iterating through the symtab easier. 188 { st_name: sizeof(ANDROID_LIBDL_STRTAB) - 1, 189 }, 190 { st_name: 0, // starting index of the name in libdl_info.strtab 191 st_value: (Elf32_Addr) &dlopen, 192 st_info: STB_GLOBAL << 4, 193 st_shndx: 1, 194 }, 195 { st_name: 7, 196 st_value: (Elf32_Addr) &dlclose, 197 st_info: STB_GLOBAL << 4, 198 st_shndx: 1, 199 }, 200 { st_name: 15, 201 st_value: (Elf32_Addr) &dlsym, 202 st_info: STB_GLOBAL << 4, 203 st_shndx: 1, 204 }, 205 { st_name: 21, 206 st_value: (Elf32_Addr) &dlerror, 207 st_info: STB_GLOBAL << 4, 208 st_shndx: 1, 209 }, 210 { st_name: 29, 211 st_value: (Elf32_Addr) &dladdr, 212 st_info: STB_GLOBAL << 4, 213 st_shndx: 1, 214 }, 215 #ifdef ANDROID_ARM_LINKER 216 { st_name: 36, 217 st_value: (Elf32_Addr) &dl_unwind_find_exidx, 218 st_info: STB_GLOBAL << 4, 219 st_shndx: 1, 220 }, 221 #elif defined(ANDROID_X86_LINKER) 222 { st_name: 36, 223 st_value: (Elf32_Addr) &dl_iterate_phdr, 224 st_info: STB_GLOBAL << 4, 225 st_shndx: 1, 226 }, 227 #endif 228 }; 229 230 /* Fake out a hash table with a single bucket. 231 * A search of the hash table will look through 232 * libdl_symtab starting with index [1], then 233 * use libdl_chains to find the next index to 234 * look at. libdl_chains should be set up to 235 * walk through every element in libdl_symtab, 236 * and then end with 0 (sentinel value). 237 * 238 * I.e., libdl_chains should look like 239 * { 0, 2, 3, ... N, 0 } where N is the number 240 * of actual symbols, or nelems(libdl_symtab)-1 241 * (since the first element of libdl_symtab is not 242 * a real symbol). 243 * 244 * (see _elf_lookup()) 245 * 246 * Note that adding any new symbols here requires 247 * stubbing them out in libdl. 248 */ 249 static unsigned libdl_buckets[1] = { 1 }; 250 static unsigned libdl_chains[7] = { 0, 2, 3, 4, 5, 6, 0 }; 251 252 soinfo libdl_info = { 253 name: "libdl.so", 254 flags: FLAG_LINKED, 255 256 strtab: ANDROID_LIBDL_STRTAB, 257 symtab: libdl_symtab, 258 259 nbucket: 1, 260 nchain: 7, 261 bucket: libdl_buckets, 262 chain: libdl_chains, 263 }; 264 265