• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
21 /* This file hijacks the symbols stubbed out in libdl.so. */
22 
23 #define DL_SUCCESS                    0
24 #define DL_ERR_CANNOT_LOAD_LIBRARY    1
25 #define DL_ERR_INVALID_LIBRARY_HANDLE 2
26 #define DL_ERR_BAD_SYMBOL_NAME        3
27 #define DL_ERR_SYMBOL_NOT_FOUND       4
28 #define DL_ERR_SYMBOL_NOT_GLOBAL      5
29 
30 static char dl_err_buf[1024];
31 static const char *dl_err_str;
32 
33 static const char *dl_errors[] = {
34     [DL_ERR_CANNOT_LOAD_LIBRARY] = "Cannot load library",
35     [DL_ERR_INVALID_LIBRARY_HANDLE] = "Invalid library handle",
36     [DL_ERR_BAD_SYMBOL_NAME] = "Invalid symbol name",
37     [DL_ERR_SYMBOL_NOT_FOUND] = "Symbol not found",
38     [DL_ERR_SYMBOL_NOT_GLOBAL] = "Symbol is not global",
39 };
40 
41 #define likely(expr)   __builtin_expect (expr, 1)
42 #define unlikely(expr) __builtin_expect (expr, 0)
43 
44 static pthread_mutex_t dl_lock = PTHREAD_MUTEX_INITIALIZER;
45 
set_dlerror(int err)46 static void set_dlerror(int err)
47 {
48     snprintf(dl_err_buf, sizeof(dl_err_buf), "%s: %s", dl_errors[err],
49              linker_get_error());
50     dl_err_str = (const char *)&dl_err_buf[0];
51 };
52 
dlopen(const char * filename,int flag)53 void *dlopen(const char *filename, int flag)
54 {
55     soinfo *ret;
56 
57     pthread_mutex_lock(&dl_lock);
58     ret = find_library(filename);
59     if (unlikely(ret == NULL)) {
60         set_dlerror(DL_ERR_CANNOT_LOAD_LIBRARY);
61     } else {
62         ret->refcount++;
63     }
64     pthread_mutex_unlock(&dl_lock);
65     return ret;
66 }
67 
dlerror(void)68 const char *dlerror(void)
69 {
70     const char *tmp = dl_err_str;
71     dl_err_str = NULL;
72     return (const char *)tmp;
73 }
74 
dlsym(void * handle,const char * symbol)75 void *dlsym(void *handle, const char *symbol)
76 {
77     unsigned base;
78     Elf32_Sym *sym;
79     unsigned bind;
80 
81     pthread_mutex_lock(&dl_lock);
82 
83     if(unlikely(handle == 0)) {
84         set_dlerror(DL_ERR_INVALID_LIBRARY_HANDLE);
85         goto err;
86     }
87     if(unlikely(symbol == 0)) {
88         set_dlerror(DL_ERR_BAD_SYMBOL_NAME);
89         goto err;
90     }
91 
92     if(handle == RTLD_DEFAULT) {
93         sym = lookup(symbol, &base);
94     } else if(handle == RTLD_NEXT) {
95         sym = lookup(symbol, &base);
96     } else {
97         sym = lookup_in_library((soinfo*) handle, symbol);
98         base = ((soinfo*) handle)->base;
99     }
100 
101     if(likely(sym != 0)) {
102         bind = ELF32_ST_BIND(sym->st_info);
103 
104         if(likely((bind == STB_GLOBAL) && (sym->st_shndx != 0))) {
105             unsigned ret = sym->st_value + base;
106             pthread_mutex_unlock(&dl_lock);
107             return (void*)ret;
108         }
109 
110         set_dlerror(DL_ERR_SYMBOL_NOT_GLOBAL);
111     }
112     else
113         set_dlerror(DL_ERR_SYMBOL_NOT_FOUND);
114 
115 err:
116     pthread_mutex_unlock(&dl_lock);
117     return 0;
118 }
119 
dlclose(void * handle)120 int dlclose(void *handle)
121 {
122     pthread_mutex_lock(&dl_lock);
123     (void)unload_library((soinfo*)handle);
124     pthread_mutex_unlock(&dl_lock);
125     return 0;
126 }
127 
128 #if defined(ANDROID_ARM_LINKER)
129 //                     0000000 00011111 111112 22222222 233333333334444444444
130 //                     0123456 78901234 567890 12345678 901234567890123456789
131 #define ANDROID_LIBDL_STRTAB \
132                       "dlopen\0dlclose\0dlsym\0dlerror\0dl_unwind_find_exidx\0"
133 
134 #elif defined(ANDROID_X86_LINKER)
135 //                     0000000 00011111 111112 22222222 2333333333344444
136 //                     0123456 78901234 567890 12345678 9012345678901234
137 #define ANDROID_LIBDL_STRTAB \
138                       "dlopen\0dlclose\0dlsym\0dlerror\0dl_iterate_phdr\0"
139 
140 #else /* !defined(ANDROID_ARM_LINKER) && !defined(ANDROID_X86_LINKER) */
141 #error Unsupported architecture. Only ARM and x86 are presently supported.
142 #endif
143 
144 
145 static Elf32_Sym libdl_symtab[] = {
146       // total length of libdl_info.strtab, including trailing 0
147       // This is actually the the STH_UNDEF entry. Technically, it's
148       // supposed to have st_name == 0, but instead, it points to an index
149       // in the strtab with a \0 to make iterating through the symtab easier.
150     { st_name: sizeof(ANDROID_LIBDL_STRTAB) - 1,
151     },
152     { st_name: 0,   // starting index of the name in libdl_info.strtab
153       st_value: (Elf32_Addr) &dlopen,
154       st_info: STB_GLOBAL << 4,
155       st_shndx: 1,
156     },
157     { st_name: 7,
158       st_value: (Elf32_Addr) &dlclose,
159       st_info: STB_GLOBAL << 4,
160       st_shndx: 1,
161     },
162     { st_name: 15,
163       st_value: (Elf32_Addr) &dlsym,
164       st_info: STB_GLOBAL << 4,
165       st_shndx: 1,
166     },
167     { st_name: 21,
168       st_value: (Elf32_Addr) &dlerror,
169       st_info: STB_GLOBAL << 4,
170       st_shndx: 1,
171     },
172 #ifdef ANDROID_ARM_LINKER
173     { st_name: 29,
174       st_value: (Elf32_Addr) &dl_unwind_find_exidx,
175       st_info: STB_GLOBAL << 4,
176       st_shndx: 1,
177     },
178 #elif defined(ANDROID_X86_LINKER)
179     { st_name: 29,
180       st_value: (Elf32_Addr) &dl_iterate_phdr,
181       st_info: STB_GLOBAL << 4,
182       st_shndx: 1,
183     },
184 #endif
185 };
186 
187 /* Fake out a hash table with a single bucket.
188  * A search of the hash table will look through
189  * libdl_symtab starting with index [1], then
190  * use libdl_chains to find the next index to
191  * look at.  libdl_chains should be set up to
192  * walk through every element in libdl_symtab,
193  * and then end with 0 (sentinel value).
194  *
195  * I.e., libdl_chains should look like
196  * { 0, 2, 3, ... N, 0 } where N is the number
197  * of actual symbols, or nelems(libdl_symtab)-1
198  * (since the first element of libdl_symtab is not
199  * a real symbol).
200  *
201  * (see _elf_lookup())
202  *
203  * Note that adding any new symbols here requires
204  * stubbing them out in libdl.
205  */
206 static unsigned libdl_buckets[1] = { 1 };
207 static unsigned libdl_chains[6] = { 0, 2, 3, 4, 5, 0 };
208 
209 soinfo libdl_info = {
210     name: "libdl.so",
211     flags: FLAG_LINKED,
212 
213     strtab: ANDROID_LIBDL_STRTAB,
214     symtab: libdl_symtab,
215 
216     nbucket: 1,
217     nchain: 6,
218     bucket: libdl_buckets,
219     chain: libdl_chains,
220 };
221 
222