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 static pthread_mutex_t dl_lock = PTHREAD_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 ret->refcount++; 64 } 65 pthread_mutex_unlock(&dl_lock); 66 return ret; 67 } 68 69 const char *dlerror(void) 70 { 71 const char *tmp = dl_err_str; 72 dl_err_str = NULL; 73 return (const char *)tmp; 74 } 75 76 void *dlsym(void *handle, const char *symbol) 77 { 78 soinfo *found; 79 Elf32_Sym *sym; 80 unsigned bind; 81 82 pthread_mutex_lock(&dl_lock); 83 84 if(unlikely(handle == 0)) { 85 set_dlerror(DL_ERR_INVALID_LIBRARY_HANDLE); 86 goto err; 87 } 88 if(unlikely(symbol == 0)) { 89 set_dlerror(DL_ERR_BAD_SYMBOL_NAME); 90 goto err; 91 } 92 93 if(handle == RTLD_DEFAULT) { 94 sym = lookup(symbol, &found, NULL); 95 } else if(handle == RTLD_NEXT) { 96 void *ret_addr = __builtin_return_address(0); 97 soinfo *si = find_containing_library(ret_addr); 98 99 sym = NULL; 100 if(si && si->next) { 101 sym = lookup(symbol, &found, si->next); 102 } 103 } else { 104 found = (soinfo*)handle; 105 sym = lookup_in_library(found, symbol); 106 } 107 108 if(likely(sym != 0)) { 109 bind = ELF32_ST_BIND(sym->st_info); 110 111 if(likely((bind == STB_GLOBAL) && (sym->st_shndx != 0))) { 112 unsigned ret = sym->st_value + found->base; 113 pthread_mutex_unlock(&dl_lock); 114 return (void*)ret; 115 } 116 117 set_dlerror(DL_ERR_SYMBOL_NOT_GLOBAL); 118 } 119 else 120 set_dlerror(DL_ERR_SYMBOL_NOT_FOUND); 121 122 err: 123 pthread_mutex_unlock(&dl_lock); 124 return 0; 125 } 126 127 int dladdr(const void *addr, Dl_info *info) 128 { 129 int ret = 0; 130 131 pthread_mutex_lock(&dl_lock); 132 133 /* Determine if this address can be found in any library currently mapped */ 134 soinfo *si = find_containing_library(addr); 135 136 if(si) { 137 memset(info, 0, sizeof(Dl_info)); 138 139 info->dli_fname = si->name; 140 info->dli_fbase = (void*)si->base; 141 142 /* Determine if any symbol in the library contains the specified address */ 143 Elf32_Sym *sym = find_containing_symbol(addr, si); 144 145 if(sym != NULL) { 146 info->dli_sname = si->strtab + sym->st_name; 147 info->dli_saddr = (void*)(si->base + sym->st_value); 148 } 149 150 ret = 1; 151 } 152 153 pthread_mutex_unlock(&dl_lock); 154 155 return ret; 156 } 157 158 int dlclose(void *handle) 159 { 160 pthread_mutex_lock(&dl_lock); 161 (void)unload_library((soinfo*)handle); 162 pthread_mutex_unlock(&dl_lock); 163 return 0; 164 } 165 166 #if defined(ANDROID_ARM_LINKER) 167 // 0000000 00011111 111112 22222222 2333333 333344444444445555555 168 // 0123456 78901234 567890 12345678 9012345 678901234567890123456 169 #define ANDROID_LIBDL_STRTAB \ 170 "dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0dl_unwind_find_exidx\0" 171 172 #elif defined(ANDROID_X86_LINKER) 173 // 0000000 00011111 111112 22222222 2333333 3333444444444455 174 // 0123456 78901234 567890 12345678 9012345 6789012345678901 175 #define ANDROID_LIBDL_STRTAB \ 176 "dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0dl_iterate_phdr\0" 177 178 #elif defined(ANDROID_SH_LINKER) 179 // 0000000 00011111 111112 22222222 2333333 3333444444444455 180 // 0123456 78901234 567890 12345678 9012345 6789012345678901 181 #define ANDROID_LIBDL_STRTAB \ 182 "dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0dl_iterate_phdr\0" 183 184 #else /* !defined(ANDROID_ARM_LINKER) && !defined(ANDROID_X86_LINKER) */ 185 #error Unsupported architecture. Only ARM and x86 are presently supported. 186 #endif 187 188 189 static Elf32_Sym libdl_symtab[] = { 190 // total length of libdl_info.strtab, including trailing 0 191 // This is actually the the STH_UNDEF entry. Technically, it's 192 // supposed to have st_name == 0, but instead, it points to an index 193 // in the strtab with a \0 to make iterating through the symtab easier. 194 { st_name: sizeof(ANDROID_LIBDL_STRTAB) - 1, 195 }, 196 { st_name: 0, // starting index of the name in libdl_info.strtab 197 st_value: (Elf32_Addr) &dlopen, 198 st_info: STB_GLOBAL << 4, 199 st_shndx: 1, 200 }, 201 { st_name: 7, 202 st_value: (Elf32_Addr) &dlclose, 203 st_info: STB_GLOBAL << 4, 204 st_shndx: 1, 205 }, 206 { st_name: 15, 207 st_value: (Elf32_Addr) &dlsym, 208 st_info: STB_GLOBAL << 4, 209 st_shndx: 1, 210 }, 211 { st_name: 21, 212 st_value: (Elf32_Addr) &dlerror, 213 st_info: STB_GLOBAL << 4, 214 st_shndx: 1, 215 }, 216 { st_name: 29, 217 st_value: (Elf32_Addr) &dladdr, 218 st_info: STB_GLOBAL << 4, 219 st_shndx: 1, 220 }, 221 #ifdef ANDROID_ARM_LINKER 222 { st_name: 36, 223 st_value: (Elf32_Addr) &dl_unwind_find_exidx, 224 st_info: STB_GLOBAL << 4, 225 st_shndx: 1, 226 }, 227 #elif defined(ANDROID_X86_LINKER) 228 { st_name: 36, 229 st_value: (Elf32_Addr) &dl_iterate_phdr, 230 st_info: STB_GLOBAL << 4, 231 st_shndx: 1, 232 }, 233 #elif defined(ANDROID_SH_LINKER) 234 { st_name: 36, 235 st_value: (Elf32_Addr) &dl_iterate_phdr, 236 st_info: STB_GLOBAL << 4, 237 st_shndx: 1, 238 }, 239 #endif 240 }; 241 242 /* Fake out a hash table with a single bucket. 243 * A search of the hash table will look through 244 * libdl_symtab starting with index [1], then 245 * use libdl_chains to find the next index to 246 * look at. libdl_chains should be set up to 247 * walk through every element in libdl_symtab, 248 * and then end with 0 (sentinel value). 249 * 250 * I.e., libdl_chains should look like 251 * { 0, 2, 3, ... N, 0 } where N is the number 252 * of actual symbols, or nelems(libdl_symtab)-1 253 * (since the first element of libdl_symtab is not 254 * a real symbol). 255 * 256 * (see _elf_lookup()) 257 * 258 * Note that adding any new symbols here requires 259 * stubbing them out in libdl. 260 */ 261 static unsigned libdl_buckets[1] = { 1 }; 262 static unsigned libdl_chains[7] = { 0, 2, 3, 4, 5, 6, 0 }; 263 264 soinfo libdl_info = { 265 name: "libdl.so", 266 flags: FLAG_LINKED, 267 268 strtab: ANDROID_LIBDL_STRTAB, 269 symtab: libdl_symtab, 270 271 nbucket: 1, 272 nchain: 7, 273 bucket: libdl_buckets, 274 chain: libdl_chains, 275 }; 276 277