~sergiusens/libhybris/autotests

« back to all changes in this revision

Viewing changes to hybris/common/jb/dlfcn.c

  • Committer: Package Import Robot
  • Author(s): Ricardo Salveti de Araujo
  • Date: 2013-06-04 07:33:11 UTC
  • Revision ID: package-import@ubuntu.com-20130604073311-20ldi2hm1axkvjl1
Tags: upstream-0.1.0+git20130601+dfb2e26
ImportĀ upstreamĀ versionĀ 0.1.0+git20130601+dfb2e26

Show diffs side-by-side

added added

removed removed

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